#include "MySqlStatementParser.h"
#include "MySqlExprParser.h"
#include "MySqlSelectParser.h"
#include "MySqlCreateTableParser.h"
#include "../ast/statement/MySqlCreateTableStatement.h"
#include "../../../parser/SQLStatementParser.h"
#include "../../../ast/statement/SQLSelectStatement.h"
#include "../../../ast/statement/SQLCreateDatabaseStatement.h"
#include "../../../ast/statement/SQLUpdateStatement.h"
#include "../../../../utils/FnvHash.h"
#include "../../../../utils/StringUtils.h"
#include "../../../../utils/instanceof.h"
#include "../../../../utils/log.h"

#include "../ast/statement/MySqlUpdateStatement.h"
#include "../../../ast/statement/SQLCreateTableStatement.h"
#include "../../../ast/statement/SQLLoopStatement.h"
#include "../../../ast/statement/SQLWhileStatement.h"
#include "../../../ast/statement/SQLBlockStatement.h"
#include "../../../ast/statement/SQLCommitStatement.h"
#include "../ast/clause/MySqlRepeatStatement.h"
#include "../../../ast/statement/SQLRollbackStatement.h"
#include "../ast/statement/MySqlInsertStatement.h"
#include "../../../parser/InsertColumnsCache.h"
#include "../../../repository/SchemaRepository.h"
#include "../../../repository/SchemaObject.h"
#include "../../../visitor/SQLASTOutputVisitor.h"
#include "../../../parser/SQLParserFeature.h"

string_ptr MySqlStatementParser::AUTO_INCREMENT = make_string_ptr("AUTO_INCREMENT");
string_ptr MySqlStatementParser::AVG_ROW_LENGTH = make_string_ptr("AVG_ROW_LENGTH");
string_ptr MySqlStatementParser::CHECKSUM2 = make_string_ptr("CHECKSUM");
string_ptr MySqlStatementParser::DELAY_KEY_WRITE = make_string_ptr("DELAY_KEY_WRITE");
string_ptr MySqlStatementParser::ENCRYPTION2 = make_string_ptr("ENCRYPTION");
string_ptr MySqlStatementParser::INSERT_METHOD = make_string_ptr("INSERT_METHOD");
string_ptr MySqlStatementParser::KEY_BLOCK_SIZE2 = make_string_ptr("KEY_BLOCK_SIZE");
string_ptr MySqlStatementParser::MAX_ROWS2 = make_string_ptr("MAX_ROWS");
string_ptr MySqlStatementParser::MIN_ROWS2 = make_string_ptr("MIN_ROWS");
string_ptr MySqlStatementParser::PASSWORD2 = make_string_ptr("PASSWORD");
string_ptr MySqlStatementParser::STATS_AUTO_RECALC = make_string_ptr("STATS_AUTO_RECALC");
string_ptr MySqlStatementParser::STATS_PERSISTENT = make_string_ptr("STATS_PERSISTENT");
string_ptr MySqlStatementParser::STATS_SAMPLE_PAGES = make_string_ptr("STATS_SAMPLE_PAGES");
string_ptr MySqlStatementParser::TABLESPACE2 = make_string_ptr("TABLESPACE");
string_ptr MySqlStatementParser::CHAIN = make_string_ptr("CHAIN");
string_ptr MySqlStatementParser::ENGINES = make_string_ptr("ENGINES");
string_ptr MySqlStatementParser::ENGINE = make_string_ptr("ENGINE");
string_ptr MySqlStatementParser::BINLOG = make_string_ptr("BINLOG");
string_ptr MySqlStatementParser::EVENTS = make_string_ptr("EVENTS");
string_ptr MySqlStatementParser::GLOBAL = make_string_ptr("GLOBAL");
string_ptr MySqlStatementParser::VARIABLES = make_string_ptr("VARIABLES");
string_ptr MySqlStatementParser::STATUS = make_string_ptr("STATUS");
string_ptr MySqlStatementParser::DBLOCK = make_string_ptr("DBLOCK");
string_ptr MySqlStatementParser::RESET = make_string_ptr("RESET");
string_ptr MySqlStatementParser::DESCRIBE = make_string_ptr("DESCRIBE");
string_ptr MySqlStatementParser::WRITE = make_string_ptr("WRITE");
string_ptr MySqlStatementParser::READ = make_string_ptr("READ");
string_ptr MySqlStatementParser::LOCAL = make_string_ptr("LOCAL");
string_ptr MySqlStatementParser::TABLES = make_string_ptr("TABLES");
string_ptr MySqlStatementParser::CONNECTION = make_string_ptr("CONNECTION");

MySqlStatementParser::MySqlStatementParser(string_ptr sql)
    : SQLStatementParser(MySqlExprParser_ptr(new MySqlExprParser(sql)))
{
}

MySqlStatementParser::MySqlStatementParser(string_ptr sql, SQLParserFeature_list_ptr features)
    : SQLStatementParser(MySqlExprParser_ptr(new MySqlExprParser(sql, features)))
{
  LOG_INFO;
}

MySqlStatementParser::MySqlStatementParser(string_ptr sql, BOOL_ptr keepComments)
    : SQLStatementParser(MySqlExprParser_ptr(new MySqlExprParser(sql, keepComments)))
{
}

MySqlStatementParser::MySqlStatementParser(string_ptr sql, BOOL_ptr skipComment, BOOL_ptr keepComments)
    : SQLStatementParser(MySqlExprParser_ptr(new MySqlExprParser(sql, skipComment, keepComments)))
{
}

MySqlStatementParser::MySqlStatementParser(Lexer_ptr lexer)
    : SQLStatementParser(MySqlExprParser_ptr(new MySqlExprParser(lexer)))
{
}

int MySqlStatementParser::getMaxIntoClause()
{
  return maxIntoClause;
}

void MySqlStatementParser::setMaxIntoClause(int maxIntoClause)
{
  this->maxIntoClause = maxIntoClause;
}

SQLCreateTableStatement_ptr MySqlStatementParser::parseCreateTable()
{
  MySqlCreateTableParser *parser = new MySqlCreateTableParser(this->exprParser);
  return parser->parseCreateTable();
}

SQLStatement_ptr MySqlStatementParser::parseSelect()
{
  LOG_INFO << "in parseSelect";
  MySqlSelectParser_ptr selectParser = createSQLSelectParser();

  SQLSelect_ptr select = selectParser->select();

  if (selectParser->returningFlag)
  {
    return selectParser->updateStmt;
  }

  return SQLSelectStatement_ptr(new SQLSelectStatement(select, DbType_ptr(new DbType(&DbType::mysql))));
  // return nullptr;
}

SQLUpdateStatement_ptr MySqlStatementParser::parseUpdateStatement()
{
  return (new MySqlSelectParser(this->exprParser, selectListCache))->parseUpdateStatment();
}

SQLUpdateStatement_ptr MySqlStatementParser::createUpdateStatement()
{
  return SQLUpdateStatement_ptr(new MySqlUpdateStatement());
}

// MySqlDeleteStatement* MySqlStatementParser::parseDeleteStatement() {
//     MySqlDeleteStatement* deleteStatement = new MySqlDeleteStatement();

//     if (lexer->isKeepComments() && lexer->hasComment()) {
//         std::list<string_ptr > comments = lexer->readAndResetComments();

//         if (!comments.empty()) {
//             deleteStatement.addBeforeComment(comments);
//         }
//     }

//     if (lexer->token()->name->c_str() == Token::DELETE) {
//         lexer->nextToken();

//         if (lexer->token()->name->c_str() == Token::COMMENT.name->c_str()) {
//             lexer->nextToken();
//         }

//         if (lexer->token()->name->c_str() == Token::HINT.name->c_str()) {
//             this->getExprParser().parseHints(deleteStatement.getHints());
//         }

//         if (lexer->identifierEquals(FnvHash::Constants::LOW_PRIORITY)) {
//             deleteStatement.setLowPriority(BOOL::TRUE);
//             lexer->nextToken();
//         }

//         if (lexer->identifierEquals("QUICK")) {
//             deleteStatement.setQuick(BOOL::TRUE);
//             lexer->nextToken();
//         }

//         if (lexer->identifierEquals(FnvHash::Constants::IGNORE)) {
//             deleteStatement.setIgnore(BOOL::TRUE);
//             lexer->nextToken();
//         }

//         if (lexer->identifierEquals(FnvHash::Constants::FORCE)) {
//             Lexer::SavePoint savePoint = lexer->mark();
//             lexer->nextToken();

//             if (lexer->token()->name->c_str() == Token::ALL) {
//                 lexer->nextToken();
//                 acceptIdentifier("PARTITIONS");
//                 deleteStatement.setForceAllPartitions(BOOL::TRUE);
//             } else if (lexer->identifierEquals(FnvHash::Constants::PARTITIONS)) {
//                 lexer->nextToken();
//                 deleteStatement.setForceAllPartitions(BOOL::TRUE);
//             } else if (lexer->token()->name->c_str() == Token::PARTITION.name->c_str()) {
//                 lexer->nextToken();
//                 SQLName_ptr  partition = this->exprParser->name();
//                 deleteStatement.setForcePartition(partition);
//             } else {
//                 lexer->reset(savePoint);
//             }
//         }

//         if (lexer->token()->name->c_str() == Token::IDENTIFIER.name->c_str()) {
//             deleteStatement.setTableSource(createSQLSelectParser().parseTableSource());

//             if (lexer->token()->name->c_str() == Token::FROM.name->c_str()) {
//                 lexer->nextToken();
//                 SQLTableSource tableSource = createSQLSelectParser().parseTableSource();
//                 deleteStatement.setFrom(tableSource);
//             }
//         } else if (lexer->token()->name->c_str() == Token::FROM.name->c_str()) {
//             lexer->nextToken();

//             if (lexer->token()->name->c_str() == Token::FULLTEXT.name->c_str()) {
//                 lexer->nextToken();
//                 if (lexer->identifierEquals(FnvHash::Constants::DICTIONARY)) {
//                     lexer->nextToken();
//                     deleteStatement.setFulltextDictionary(BOOL::TRUE);
//                 }
//             }

//             deleteStatement.setTableSource(createSQLSelectParser().parseTableSource());
//         } else {
//             throw new ParserException("syntax error. " + lexer->info());
//         }

//         if (lexer->identifierEquals(FnvHash::Constants::USING)) {
//             lexer->nextToken();

//             SQLTableSource tableSource = createSQLSelectParser().parseTableSource();
//             deleteStatement.setUsing(tableSource);
//         }
//     }

//     if (lexer->token()->name->c_str() == (Token::WHERE)) {
//         lexer->nextToken();
//         SQLExpr_ptr where = this->exprParser->getExpr();
//         deleteStatement.setWhere(where);
//     }

//     if (lexer->token()->name->c_str() == (Token::ORDER)) {
//         SQLOrderBy* orderBy = exprParser->parseOrderBy();
//         deleteStatement.setOrderBy(orderBy);
//     }

//     if (lexer->token()->name->c_str() == Token::LIMIT.name->c_str()) {
//         deleteStatement.setLimit(this->exprParser->parseLimit());
//     }

//     if (lexer->token()->name->c_str() != Token::XEOF && lexer->token() != Token::SEMI) {
//         throw new ParserException("syntax error. " + lexer->info());
//     }

//     return deleteStatement;
// }

SQLStatement_ptr MySqlStatementParser::parseCreate()
{
  wstring_list_ptr comments = std::make_shared<std::list<wstring_ptr>>();
  if (lexer->isKeepComments() && lexer->hasComment())
  {
    comments = lexer->readAndResetComments();
  }

  Lexer_SavePoint_ptr mark = lexer->mark();

  accept(Token::CREATE);

  BOOL_ptr replace = BOOL::FALSE;
  if (lexer->token()->name->c_str() == Token::OR.name->c_str())
  {
    lexer->nextToken();
    accept(Token::REPLACE);
    replace = BOOL::TRUE;
  }

  BOOL_ptr physical = BOOL::FALSE;
  if (lexer->identifierEquals(FnvHash::Constants::PHYSICAL))
  {
    lexer->nextToken();
    physical = BOOL::TRUE;
  }

  if (lexer->token()->name->c_str() == Token::GROUP.name->c_str())
  {
    lexer->nextToken();
  }
  else if (lexer->identifierEquals(FnvHash::Constants::SIMPLE))
  {
    lexer->nextToken();
    if (lexer->token()->name->c_str() == Token::WITH.name->c_str())
    {
      lexer->nextToken();
      accept(Token::CACHE);
    }
  }
  else if (lexer->identifierEquals(FnvHash::Constants::TIME))
  {
    lexer->nextToken();
    if (lexer->token()->name->c_str() == Token::SEQUENCE.name->c_str())
    {
      lexer->reset(mark);
      return parseCreateSequence(BOOL::TRUE);
    }
  }

  SQLCommentHint_list_ptr hints = this->exprParser->parseHints();

  BOOL_ptr isExternal = BOOL::FALSE;
  if (lexer->identifierEquals(FnvHash::Constants::EXTERNAL))
  {
    isExternal = BOOL::TRUE;

    lexer->nextToken();
    if (lexer->identifierEquals(FnvHash::Constants::CATALOG))
    {
      lexer->reset(mark);
      return SQLStatementParser::parseCreateExternalCatalog();
    }
  }

  if (lexer->token()->name->c_str() == Token::TABLE.name->c_str() ||
      lexer->identifierEquals(FnvHash::Constants::TEMPORARY) ||
      isExternal ||
      lexer->identifierEquals(L"SHADOW"))
  {
    lexer->reset(mark);
    MySqlCreateTableParser *parser = new MySqlCreateTableParser(this->exprParser);
    MySqlCreateTableStatement_ptr stmt = parser->parseCreateTable(BOOL::TRUE);
    stmt->setHints(hints);

    if (!comments->empty())
    {
      stmt->addBeforeComment(comments);
    }

    return stmt;
  }

  if (lexer->token()->name->c_str() == Token::DATABASE.name->c_str() ||
      lexer->token()->name->c_str() == Token::SCHEMA.name->c_str())
  {
    if (replace)
    {
      lexer->reset(mark);
    }
    // SQLCreateDatabaseStatement stmt = (SQLCreateDatabaseStatement) parseCreateDatabase();
    // if (physical) {
    //     stmt->setPhysical(BOOL::TRUE);
    // }
    // return stmt;
  }
  else if (lexer->token()->name->c_str() == Token::USER.name->c_str())
  {
    if (replace)
    {
      lexer->reset(mark);
    }
    return parseCreateUser();
  }
  else if (lexer->token()->name->c_str() == Token::TRIGGER.name->c_str())
  {
    lexer->reset(mark);
    return parseCreateTrigger();
  }
  else if (lexer->token()->name->c_str() == Token::PROCEDURE.name->c_str())
  {
    if (replace)
    {
      lexer->reset(mark);
    }
    // return parseCreateProcedure();
  }
  else if (lexer->token()->name->c_str() == Token::FUNCTION.name->c_str())
  {
    if (replace)
    {
      lexer->reset(mark);
    }
    // return parseCreateFunction();
  }
  else if (lexer->token()->name->c_str() == Token::SEQUENCE.name->c_str())
  {
    lexer->reset(mark);
    return parseCreateSequence(BOOL::TRUE);
  }
  else if (lexer->token()->name->c_str() == Token::FULLTEXT.name->c_str())
  {
    lexer->reset(mark);
    return parseCreateFullTextStatement();
  }

  if (lexer->token()->name->c_str() == Token::UNIQUE.name->c_str() ||
      lexer->token()->name->c_str() == Token::INDEX.name->c_str() ||
      lexer->token()->name->c_str() == Token::FULLTEXT.name->c_str() ||
      lexer->identifierEquals(FnvHash::Constants::SPATIAL) ||
      lexer->identifierEquals(FnvHash::Constants::ANN) ||
      lexer->identifierEquals(FnvHash::Constants::GLOBAL) ||
      lexer->identifierEquals(FnvHash::Constants::LOCAL))
  {
    if (replace)
    {
      lexer->reset(mark);
    }
    // return parseCreateIndex(BOOL::FALSE);
  }

  if (lexer->token()->name->c_str() == Token::VIEW.name->c_str() || lexer->identifierEquals(FnvHash::Constants::ALGORITHM))
  {
    if (replace)
    {
      lexer->reset(mark);
    }

    // return parseCreateView();
  }

  if (lexer->identifierEquals(FnvHash::Constants::EVENT))
  {
    lexer->reset(mark);
    return parseCreateEvent();
  }

  if (lexer->identifierEquals(FnvHash::Constants::DEFINER))
  {
    //            Lexer::SavePoint savePoint = lexer->mark();
    lexer->nextToken();
    accept(Token::EQ);
    // this->getExprParser()->userName();

    if (lexer->identifierEquals(FnvHash::Constants::SQL))
    {
      lexer->nextToken();
      acceptIdentifier("SECURITY");
      if (lexer->token()->name->c_str() == Token::EQ.name->c_str())
      {
        lexer->nextToken();
      }
      lexer->nextToken();
    }
    if (lexer->identifierEquals(FnvHash::Constants::EVENT))
    {
      lexer->reset(mark);
      return parseCreateEvent();
    }
    else if (lexer->token()->name->c_str() == Token::TRIGGER.name->c_str())
    {
      lexer->reset(mark);
      return parseCreateTrigger();
    }
    else if (lexer->token()->name->c_str() == Token::VIEW.name->c_str())
    {
      lexer->reset(mark);
      // return SQLStatementParser::parseCreateView();
    }
    else if (lexer->token()->name->c_str() == Token::FUNCTION.name->c_str())
    {
      lexer->reset(mark);
      // return dynamic_cast<SQLStatement_ptr >(parseCreateFunction());
    }
    else
    {
      lexer->reset(mark);
      return parseCreateProcedure();
    }
  }

  if (lexer->identifierEquals(FnvHash::Constants::LOGFILE))
  {
    return parseCreateLogFileGroup();
  }

  if (lexer->identifierEquals(FnvHash::Constants::SERVER))
  {
    return parseCreateServer();
  }

  if (lexer->token()->name->c_str() == Token::TABLESPACE.name->c_str())
  {
    return parseCreateTableSpace();
  }

  if (lexer->identifierEquals(FnvHash::Constants::DIMENSION))
  {
    lexer->reset(mark);
    // return parseCreateTable();
  }

  if (lexer->identifierEquals(FnvHash::Constants::TABLEGROUP))
  {
    lexer->reset(mark);
    return parseCreateTableGroup();
  }

  if (lexer->identifierEquals(FnvHash::Constants::OUTLINE))
  {
    lexer->reset(mark);
    return parseCreateOutline();
  }

  if (lexer->identifierEquals(FnvHash::Constants::CLUSTERED))
  {
    lexer->reset(mark);
    // return parseCreateIndex(BOOL::TRUE);
  }

  if (lexer->identifierEquals(FnvHash::Constants::RESOURCE))
  {
    lexer->reset(mark);
    return parseCreateResourceGroup();
  }

  if (lexer->identifierEquals(FnvHash::Constants::MATERIALIZED))
  {
    lexer->reset(mark);
    return parseCreateMaterializedView();
  }

  if (lexer->identifierEquals(FnvHash::Constants::ROLE))
  {
    lexer->reset(mark);
    return parseCreateRole();
  }

  throw new ParserException(make_string_ptr("TODO " + encode_util::UnicodeToUTF8(lexer->info())));
}

SQLStatement_ptr MySqlStatementParser::parseCreateFullTextStatement()
{
  Lexer_SavePoint_ptr mark = lexer->mark();

  accept(Token::CREATE);
  accept(Token::FULLTEXT);

  if (lexer->identifierEquals(FnvHash::Constants::CHARFILTER))
  {
    lexer->nextToken();
    return parseFullTextCharFilter();
  }
  else if (lexer->identifierEquals(FnvHash::Constants::TOKENIZER))
  {
    lexer->nextToken();
    return parseFullTextTokenizer();
  }
  else if (lexer->identifierEquals(FnvHash::Constants::TOKENFILTER))
  {
    lexer->nextToken();
    return parseFullTextTokenFilter();
  }
  else if (lexer->identifierEquals(FnvHash::Constants::ANALYZER))
  {
    lexer->nextToken();
    return parseFullTextAnalyzer();
  }
  else if (lexer->token()->name->c_str() == Token::INDEX.name->c_str())
  {
    lexer->reset(mark);
    // return parseCreateIndex(BOOL::TRUE);
  }
  else if (lexer->identifierEquals(FnvHash::Constants::DICTIONARY))
  {
    lexer->nextToken();
    // MysqlCreateFullTextDictionaryStatement stmt = new MysqlCreateFullTextDictionaryStatement();
    SQLName_ptr name = this->exprParser->name();
    // stmt->setName(name);

    accept(Token::LPAREN);

    SQLColumnDefinition *col = new SQLColumnDefinition();

    col->setName(this->exprParser->name());

    acceptIdentifier("varchar");

    string_ptr tmp = make_string_ptr("varchar");
    col->setDataType(SQLDataType_ptr(new SQLDataTypeImpl(tmp)));

    if (lexer->token()->name->c_str() == Token::COMMENT.name->c_str())
    {
      accept(Token::COMMENT);
      col->setComment(this->exprParser->name());
    }

    // stmt->setColumn(col);
    accept(Token::RPAREN);

    if (lexer->token()->name->c_str() == Token::COMMENT.name->c_str())
    {
      accept(Token::COMMENT);
      // stmt->setComment(this->exprParser->name().getSimpleName());
    }
    // return stmt;
  }
  throw new ParserException(make_string_ptr("TODO " + encode_util::UnicodeToUTF8(lexer->info())));
}

SQLStatement_ptr MySqlStatementParser::parseFullTextAnalyzer()
{
  // MysqlCreateFullTextAnalyzerStatement* stmt = new MysqlCreateFullTextAnalyzerStatement();

  SQLName_ptr name = this->exprParser->name();
  // stmt->setName(name);

  accept(Token::LPAREN);
  for (;;)
  {
    string_ptr key = make_string_ptr("");
    if (lexer->token()->name->c_str() == Token::LITERAL_ALIAS.name->c_str() ||
        lexer->token()->name->c_str() == Token::LITERAL_CHARS.name->c_str())
    {
      key = StringUtils::removeNameQuotes(make_string_ptr(encode_util::UnicodeToUTF8(*lexer->stringVal())));

      if (StringUtils::iequals(*key, "charfilter"))
      {
        lexer->nextToken();
        accept(Token::EQ);

        accept(Token::LBRACKET);
        for (;;)
        {
          string_ptr c = SQLUtils::normalize(this->exprParser->name()->getSimpleName());
          // stmt->getCharfilters().add(c);
          if (lexer->token()->name->c_str() == Token::COMMA.name->c_str())
          {
            lexer->nextToken();
            continue;
          }
          break;
        }
        accept(Token::RBRACKET);
      }
      else if (StringUtils::iequals(*key, "tokenfilter"))
      {
        lexer->nextToken();
        accept(Token::EQ);

        accept(Token::LBRACKET);
        for (;;)
        {
          string_ptr c = SQLUtils::normalize(this->exprParser->name()->getSimpleName());
          // stmt->getTokenizers().add(c);
          if (lexer->token()->name->c_str() == Token::COMMA.name->c_str())
          {
            lexer->nextToken();
            continue;
          }
          break;
        }
        accept(Token::RBRACKET);
      }
      else if (StringUtils::iequals(*key, "tokenizer"))
      {
        lexer->nextToken();
        accept(Token::EQ);

        // stmt->setTokenizer(SQLUtils::normalize(this->exprParser->name()->getSimpleName()));
      }
    }

    if (lexer->token()->name->c_str() == Token::COMMA.name->c_str())
    {
      lexer->nextToken();
      continue;
    }

    break;
  }

  accept(Token::RPAREN);

  // string_ptr  tokenizer = stmt->getTokenizer();
  // if (tokenizer.empty() || StringUtils::isEmpty(tokenizer)) {
  //     throw new ParserException("tokenizer is require.");
  // }

  // return stmt;
  return nullptr;
}

SQLStatement_ptr MySqlStatementParser::parseFullTextTokenizer()
{
  // MysqlCreateFullTextTokenizerStatement* stmt = new MysqlCreateFullTextTokenizerStatement();

  SQLName_ptr name = this->exprParser->name();
  // stmt->setName(name);

  accept(Token::LPAREN);
  for (;;)
  {
    SQLAssignItem_ptr assignItem = this->exprParser->parseAssignItem();
    // assignItem.setParent(stmt);

    SQLExpr_ptr target = assignItem->getTarget();
    if (StringUtils::iequals("type", *(std::dynamic_pointer_cast<SQLTextLiteralExpr>(target))->getText()))
    {
      // stmt->setTypeName(dynamic_cast<SQLTextLiteralExpr*>(assignItem->getValue()) );
    }
    else if (StringUtils::iequals("user_defined_dict", *(std::dynamic_pointer_cast<SQLTextLiteralExpr>(target))->getText()))
    {
      // stmt->setUserDefinedDict((SQLTextLiteralExpr*) assignItem.getValue());
    }
    else
    {
      // stmt->getOptions().add(assignItem);
    }

    if (lexer->token()->name->c_str() == Token::COMMA.name->c_str())
    {
      lexer->nextToken();
      continue;
    }
    break;
  }

  accept(Token::RPAREN);

  // SQLTextLiteralExpr* typeName = stmt->getTypeName();
  // if (typeName == nullptr || StringUtils::isEmpty(typeName->getText())) {
  //     throw new ParserException("type is require.");
  // }

  // return stmt;
  return nullptr;
}

SQLStatement_ptr MySqlStatementParser::parseFullTextCharFilter()
{
  // MysqlCreateFullTextCharFilterStatement stmt = new MysqlCreateFullTextCharFilterStatement();

  SQLName_ptr name = this->exprParser->name();
  // stmt->setName(name);

  accept(Token::LPAREN);
  for (;;)
  {
    SQLAssignItem_ptr assignItem = this->exprParser->parseAssignItem();
    // assignItem->setParent(stmt);

    if (StringUtils::iequals("type", *(std::dynamic_pointer_cast<SQLTextLiteralExpr>(assignItem->getTarget()))->getText()))
    {
      // stmt->setTypeName((SQLTextLiteralExpr*) assignItem->getValue());
    }
    else
    {
      // stmt->getOptions().add(assignItem);
    }

    if (lexer->token()->name->c_str() == Token::COMMA.name->c_str())
    {
      lexer->nextToken();
      continue;
    }
    break;
  }

  accept(Token::RPAREN);

  // SQLTextLiteralExpr* typeName = stmt->getTypeName();
  // if (typeName == nullptr || StringUtils.isEmpty(typeName.getText())) {
  //     throw new ParserException("type is require.");
  // }

  // return stmt;
  return nullptr;
}

SQLStatement_ptr MySqlStatementParser::parseFullTextTokenFilter()
{
  // MysqlCreateFullTextTokenFilterStatement stmt = new MysqlCreateFullTextTokenFilterStatement();

  // SQLName_ptr  name = this->exprParser->name();
  // stmt->setName(name);

  // accept(Token::LPAREN);
  // for (; ; ) {
  //     SQLAssignItem assignItem = this->exprParser->parseAssignItem();
  //     assignItem.setParent(stmt);

  //     if (StringUtils::iequals("type", ((SQLTextLiteralExpr*) assignItem.getTarget()).getText())) {
  //         stmt->setTypeName((SQLTextLiteralExpr*) assignItem.getValue());
  //     } else {
  //         stmt->getOptions().add(assignItem);
  //     }

  //     if (lexer->token()->name->c_str() == Token::COMMA.name->c_str()) {
  //         lexer->nextToken();
  //         continue;
  //     }
  //     break;
  // }

  // accept(Token::RPAREN);

  // SQLTextLiteralExpr* typeName = stmt->getTypeName();
  // if (typeName == nullptr || StringUtils.isEmpty(typeName.getText())) {
  //     throw new ParserException("type is require.");
  // }

  // return stmt;
  return nullptr;
}

SQLStatement_ptr MySqlStatementParser::parseCreateOutline()
{
  accept(Token::CREATE);
  acceptIdentifier("OUTLINE");

  // SQLCreateOutlineStatement stmt = new SQLCreateOutlineStatement();
  // stmt->setDbType(dbType);

  // SQLName_ptr  name = this->exprParser->name();
  // stmt->setName(name);

  // if (lexer->token()->name->c_str() == Token::WHERE.name->c_str()) {
  //     lexer->nextToken();
  //     stmt->setWhere(this->exprParser->getExpr());
  // }

  // accept(Token::ON);

  // SQLStatement_ptr  on = this->parseStatement();
  // stmt->setOn(on);

  // accept(Token::TO);

  // SQLStatement_ptr  to = this->parseStatement();
  // stmt->setTo(to);

  // return stmt;

  return nullptr;
}

SQLStatement_ptr MySqlStatementParser::parseCreateTableSpace()
{
  if (lexer->token()->name->c_str() == Token::CREATE.name->c_str())
  {
    accept(Token::CREATE);
  }

  // MySqlCreateTableSpaceStatement stmt = new MySqlCreateTableSpaceStatement();

  // accept(Token::TABLESPACE);
  // stmt->setName(this->exprParser->name());

  // if (lexer->identifierEquals(FnvHash::Constants::ADD)) {
  //     lexer->nextToken();
  //     acceptIdentifier("DATAFILE");
  //     SQLExpr_ptr file = this->exprParser->primary();
  //     stmt->setAddDataFile(file);
  // }

  // for (; ; ) {
  //     if (lexer->identifierEquals(FnvHash::Constants::INITIAL_SIZE)) {
  //         lexer->nextToken();
  //         if (lexer->token()->name->c_str() == Token::EQ.name->c_str()) {
  //             lexer->nextToken();
  //         }
  //         SQLExpr_ptr initialSize = this->exprParser->getExpr();
  //         stmt->setInitialSize(initialSize);
  //     } else if (lexer->identifierEquals(FnvHash::Constants::FILE_BLOCK_SIZE)) {
  //         lexer->nextToken();
  //         if (lexer->token()->name->c_str() == Token::EQ.name->c_str()) {
  //             lexer->nextToken();
  //         }
  //         SQLExpr_ptr fileBlockSize = this->exprParser->getExpr();
  //         stmt->setFileBlockSize(fileBlockSize);
  //     } else if (lexer->identifierEquals(FnvHash::Constants::EXTENT_SIZE)) {
  //         lexer->nextToken();
  //         if (lexer->token()->name->c_str() == Token::EQ.name->c_str()) {
  //             lexer->nextToken();
  //         }
  //         SQLExpr_ptr extentSize = this->exprParser->getExpr();
  //         stmt->setExtentSize(extentSize);
  //     } else if (lexer->identifierEquals(FnvHash::Constants::AUTOEXTEND_SIZE)) {
  //         lexer->nextToken();
  //         if (lexer->token()->name->c_str() == Token::EQ.name->c_str()) {
  //             lexer->nextToken();
  //         }
  //         SQLExpr_ptr extentSize = this->exprParser->getExpr();
  //         stmt->setAutoExtentSize(extentSize);
  //     } else if (lexer->identifierEquals(FnvHash::Constants::MAX_SIZE)) {
  //         lexer->nextToken();
  //         if (lexer->token()->name->c_str() == Token::EQ.name->c_str()) {
  //             lexer->nextToken();
  //         }
  //         SQLExpr_ptr size = this->exprParser->getExpr();
  //         stmt->setMaxSize(size);
  //     } else if (lexer->identifierEquals(FnvHash::Constants::NODEGROUP)) {
  //         lexer->nextToken();
  //         if (lexer->token()->name->c_str() == Token::EQ.name->c_str()) {
  //             lexer->nextToken();
  //         }
  //         SQLExpr_ptr size = this->exprParser->getExpr();
  //         stmt->setNodeGroup(size);
  //     } else if (lexer->identifierEquals(FnvHash::Constants::WAIT)) {
  //         lexer->nextToken();
  //         stmt->setWait(BOOL::TRUE);
  //     } else if (lexer->identifierEquals(FnvHash::Constants::ENGINE)) {
  //         lexer->nextToken();
  //         if (lexer->token()->name->c_str() == Token::EQ.name->c_str()) {
  //             lexer->nextToken();
  //         }
  //         SQLExpr_ptr engine = this->exprParser->getExpr();
  //         stmt->setEngine(engine);
  //     } else if (lexer->token()->name->c_str() == Token::COMMENT.name->c_str()) {
  //         lexer->nextToken();
  //         SQLExpr_ptr comment = this->exprParser->getExpr();
  //         stmt->setComment(comment);
  //     } else if (lexer->token()->name->c_str() == Token::USE) {
  //         lexer->nextToken();
  //         acceptIdentifier("LOGFILE");
  //         accept(Token::GROUP);

  //         SQLExpr_ptr logFileGroup = this->exprParser->getExpr();
  //         stmt->setFileBlockSize(logFileGroup);
  //     } else {
  //         break;
  //     }
  // }
  // return stmt;

  return nullptr;
}

SQLStatement_ptr MySqlStatementParser::parseCreateServer()
{
  if (lexer->token()->name->c_str() == Token::CREATE.name->c_str())
  {
    accept(Token::CREATE);
  }

  //     MySqlCreateServerStatement* stmt = new MySqlCreateServerStatement();

  //     acceptIdentifier("SERVER");
  //     stmt->setName(this->exprParser->name());

  //     accept(Token::FOREIGN);
  //     acceptIdentifier("DATA");
  //     acceptIdentifier("WRAPPER");
  //     stmt->setForeignDataWrapper(this->exprParser->name());

  //     acceptIdentifier("OPTIONS");
  //     accept(Token::LPAREN);
  //     for (; ; ) {
  //         if (lexer->identifierEquals(FnvHash::Constants::HOST)) {
  //             lexer->nextToken();
  //             SQLExpr_ptr host = this->exprParser->getExpr();
  //             stmt->setHost(host);
  //         } else if (lexer->token()->name->c_str() == Token::USER.name->c_str()) {
  //             lexer->nextToken();
  //             SQLExpr_ptr user = this->exprParser->getExpr();
  //             stmt->setUser(user);
  //         } else if (lexer->token()->name->c_str() == Token::DATABASE) {
  //             lexer->nextToken();
  //             SQLExpr_ptr db = this->exprParser->getExpr();
  //             stmt->setDatabase(db);
  //         } else if (lexer->identifierEquals(FnvHash::Constants::PASSWORD)) {
  //             lexer->nextToken();
  //             SQLExpr_ptr pwd = this->exprParser->getExpr();
  //             stmt->setPassword(pwd);
  //         } else if (lexer->identifierEquals(FnvHash::Constants::SOCKET)) {
  //             lexer->nextToken();
  //             SQLExpr_ptr sock = this->exprParser->getExpr();
  //             stmt->setSocket(sock);
  //         } else if (lexer->identifierEquals(FnvHash::Constants::OWNER)) {
  //             lexer->nextToken();
  //             SQLExpr_ptr owner = this->exprParser->getExpr();
  //             stmt->setOwner(owner);
  //         } else if (lexer->identifierEquals(FnvHash::Constants::PORT)) {
  //             lexer->nextToken();
  //             SQLExpr_ptr port = this->exprParser->getExpr();
  //             stmt->setPort(port);
  //         }

  //         if (lexer->token()->name->c_str() == Token::COMMA.name->c_str()) {
  //             lexer->nextToken();
  //         } else {
  //             break;
  //         }
  //     }
  //     accept(Token::RPAREN);
  //     return stmt;

  return nullptr;
}

// SQLCreateIndexStatement* MySqlStatementParser::parseCreateIndex(BOOL_ptr acceptCreate) {
//     if (acceptCreate) {
//         accept(Token::CREATE);
//     }

//     SQLCreateIndexStatement* stmt = new SQLCreateIndexStatement();

//     this->exprParser->parseIndex(stmt->getIndexDefinition());

//     return stmt;
// }

// void MySqlStatementParser::parseCreateIndexUsing(SQLCreateIndexStatement* stmt) {
//     if (lexer->identifierEquals(FnvHash::Constants::USING)) {
//         lexer->nextToken();

//         if (lexer->identifierEquals(FnvHash::Constants::BTREE)) {
//             stmt->setUsing("BTREE");
//             lexer->nextToken();
//         } else if (lexer->identifierEquals(FnvHash::Constants::HASH)) {
//             stmt->setUsing("HASH");
//             lexer->nextToken();
//         } else {
//             throw new ParserException("TODO " + lexer->info());
//         }
//     }
// }

SQLStatement_ptr MySqlStatementParser::parseCreateUser()
{
  if (lexer->token()->name->c_str() == Token::CREATE.name->c_str())
  {
    lexer->nextToken();
  }

  accept(Token::USER);

  // MySqlCreateUserStatement* stmt = new MySqlCreateUserStatement();

  // if (lexer->token()->name->c_str() == Token::IF.name->c_str()) {
  //     lexer->nextToken();
  //     accept(Token::NOT);
  //     accept(Token::EXISTS);
  //     stmt->setIfNotExists(BOOL::TRUE);
  // }

  // for (; ; ) {
  //     MySqlCreateUserStatement::UserSpecification* userSpec = new MySqlCreateUserStatement::UserSpecification();

  //     if (lexer->token()->name->c_str() == Token::IF.name->c_str()) {
  //         lexer->nextToken();
  //         accept(Token::NOT);
  //         accept(Token::EXISTS);
  //         stmt->setIfNotExists(BOOL::TRUE);
  //     }

  //     SQLExpr_ptr expr = exprParser->primary());
  //     if (expr instanceof SQLCharExpr) {
  //         expr = new SQLIdentifierExpr(((SQLCharExpr) expr).getText());
  //     }

  //     if (expr instanceof SQLIdentifierExpr
  //             && lexer->token() == Token::VARIANT
  //             && lexer->stringVal().charAt(0) == '@'
  //     ) {
  //         string_ptr  str = lexer->stringVal();
  //         MySqlUserName* mySqlUserName = new MySqlUserName();
  //         mySqlUserName.setUserName(((SQLIdentifierExpr) expr).getName());
  //         mySqlUserName.setHost(str.substring(1));
  //         expr = mySqlUserName;
  //         lexer->nextToken();
  //     }

  //     userSpec.setUser(expr);

  //     if (lexer->identifierEquals(FnvHash::Constants::IDENTIFIED)) {
  //         lexer->nextToken();
  //         if (lexer->token()->name->c_str() == Token::BY) {
  //             lexer->nextToken();

  //             if (lexer->identifierEquals("PASSWORD")) {
  //                 lexer->nextToken();
  //                 userSpec.setPasswordHash(BOOL::TRUE);
  //             }

  //             SQLExpr_ptr password = this->exprParser->getExpr();
  //             if (password instanceof SQLIdentifierExpr || password instanceof SQLCharExpr) {
  //                 userSpec.setPassword(password);
  //             } else {
  //                 throw new ParserException("syntax error. invalid " + password + " expression.");
  //             }

  //         } else if (lexer->token()->name->c_str() == Token::WITH.name->c_str()) {
  //             lexer->nextToken();
  //             userSpec.setAuthPlugin(this->exprParser->getExpr());

  //             // IDENTIFIED WITH auth_plugin BY 'auth_string'
  //             // IDENTIFIED WITH auth_plugin AS 'auth_string'
  //             if (lexer->token()->name->c_str() == Token::BY ||
  //                     lexer->token() == Token::AS) {
  //                 userSpec.setPluginAs(lexer->token()->name->c_str() == Token::AS);
  //                 lexer->nextToken();

  //                 if (userSpec.isPluginAs()) {
  //                     // Remove ' because lexer don't remove it when token after as.
  //                     string_ptr  psw = lexer->stringVal();
  //                     if (psw.length() >= 2 && '\'' == psw.charAt(0) && '\'' == psw.charAt(psw.length() - 1)) {
  //                         userSpec.setPassword(new SQLCharExpr(psw.substring(1, psw.length() - 1)));
  //                     } else {
  //                         userSpec.setPassword(new SQLCharExpr(psw));
  //                     }
  //                     lexer->nextToken();
  //                 } else {
  //                     userSpec.setPassword(this->exprParser->charExpr());
  //                 }
  //             }
  //         }
  //     }

  //     stmt->addUser(userSpec);

  //     if (lexer->token()->name->c_str() == Token::COMMA.name->c_str()) {
  //         lexer->nextToken();
  //         continue;
  //     }

  //     break;
  // }

  // return stmt;
  return nullptr;
}

SQLStatement_ptr MySqlStatementParser::parseKill()
{
  accept(Token::KILL);

  // MySqlKillStatement* stmt = new MySqlKillStatement();

  // if (lexer->identifierEquals("CONNECTION")) {
  //     stmt->setType(MySqlKillStatement.Type.CONNECTION);
  //     lexer->nextToken();
  // } else if (lexer->identifierEquals(FnvHash::Constants::QUERY)
  //         || lexer->identifierEquals(FnvHash::Constants::PROCESS)) {
  //     stmt->setType(MySqlKillStatement.Type.QUERY);
  //     lexer->nextToken();
  // } else if (lexer->token()->name->c_str() == Token::LITERAL_INT
  //         || lexer->token()->name->c_str() == Token::LITERAL_CHARS
  // ) {
  //     // skip
  // } else if (lexer->token()->name->c_str() == Token::ALL) {
  //     SQLIdentifierExpr all = new SQLIdentifierExpr(lexer->stringVal());
  //     all.setParent(stmt);
  //     stmt->getThreadIds().add(all);
  //     lexer->nextToken();
  // } else {
  //     throw new ParserException("not support kill type " + lexer->token() + ". " + lexer->info());
  // }

  // this->exprParser->exprstd::list(stmt->getThreadIds(), stmt);

  // if (lexer->token()->name->c_str() == Token::SEMI.name->c_str()) {
  //     lexer->nextToken();
  //     stmt->setAfterSemi(BOOL::TRUE);
  // }
  // return stmt;

  return nullptr;
}

SQLStatement_ptr MySqlStatementParser::parseBinlog()
{
  acceptIdentifier("binlog");

  // MySqlBinlogStatement* stmt = new MySqlBinlogStatement();

  // SQLExpr_ptr expr = this->exprParser->getExpr();
  // stmt->setExpr(expr);

  // return stmt;
  return nullptr;
}

// MySqlAnalyzeStatement* MySqlStatementParser::parseAnalyze() {
//     accept(Token::ANALYZE);
//     // MySqlAnalyzeStatement* stmt = new MySqlAnalyzeStatement();

//     // if (*lexer->token() == TABLE) {
//     //     accept(Token::TABLE);
//     //     std::list<SQLName_ptr > names = new Arraystd::list<SQLName_ptr >();
//     //     this->exprParser->names(names, stmt);

//     //     for (SQLName_ptr  name : names) {
//     //         stmt->addTableSource(new SQLExprTableSource(name));
//     //     }
//     //     if (*lexer->token() == WHERE) {
//     //         accept(WHERE);
//     //         SQLExpr_ptr where = this->exprParser->getExpr();
//     //         stmt->setAdbWhere(where);
//     //     }
//     // } else if (*lexer->token() == DATABASE) {
//     //     accept(DATABASE);
//     //     SQLName_ptr  name = this->exprParser->name();
//     //     stmt->setAdbSchema((SQLIdentifierExpr) name);
//     // } else if (*lexer->token() == COLUMN) {
//     //     accept(COLUMN);
//     //     SQLName_ptr  table = this->exprParser->name();
//     //     stmt->setTable(table);

//     //     accept(LPAREN);

//     //     for (; ; ) {
//     //         SQLName_ptr  name = this->exprParser->name();
//     //         stmt->getAdbColumns().add((SQLIdentifierExpr) name);
//     //         if (*lexer->token() == COMMA) {
//     //             accept(COMMA);
//     //             continue;
//     //         }
//     //         break;
//     //     }
//     //     accept(RPAREN);
//     //     if (*lexer->token() == WHERE) {
//     //         accept(WHERE);
//     //         SQLExpr_ptr where = this->exprParser->getExpr();
//     //         stmt->setAdbWhere(where);
//     //     }
//     // } else if (lexer->identifierEquals("columns")) {
//     //     lexer->nextToken();
//     //     accept(GROUP);

//     //     SQLName_ptr  table = this->exprParser->name();
//     //     stmt->setTable(table);

//     //     accept(LPAREN);

//     //     for (; ; ) {
//     //         SQLName_ptr  name = this->exprParser->name();
//     //         stmt->getAdbColumnsGroup().add((SQLIdentifierExpr) name);
//     //         if (*lexer->token() == COMMA) {
//     //             accept(COMMA);
//     //             continue;
//     //         }
//     //         break;
//     //     }
//     //     accept(RPAREN);
//     //     if (*lexer->token() == WHERE) {
//     //         accept(WHERE);
//     //         SQLExpr_ptr where = this->exprParser->getExpr();
//     //         stmt->setAdbWhere(where);
//     //     }
//     // }

//     // if (lexer->token()->name->c_str() == Token::PARTITION.name->c_str()) {
//     //     stmt->setPartition(
//     //             parsePartitionRef()
//     //     );
//     // }

//     // if (lexer->token()->name->c_str() == Token::COMPUTE) {
//     //     lexer->nextToken();
//     //     acceptIdentifier("STATISTICS");
//     //     stmt->setComputeStatistics(BOOL::TRUE);
//     // }

//     // if (lexer->token()->name->c_str() == Token::FOR.name->c_str()) {
//     //     lexer->nextToken();
//     //     acceptIdentifier("COLUMNS");
//     //     stmt->setForColums(BOOL::TRUE);
//     // }

//     // if (lexer->identifierEquals(FnvHash::Constants::CACHE)) {
//     //     lexer->nextToken();
//     //     acceptIdentifier("METADATA");
//     //     stmt->setCacheMetadata(BOOL::TRUE);
//     // }

//     // if (lexer->identifierEquals(FnvHash::Constants::NOSCAN)) {
//     //     lexer->nextToken();
//     //     stmt->setNoscan(BOOL::TRUE);
//     // }

//     // return stmt;

//     return nullptr;
// }

// MySqlOptimizeStatement* MySqlStatementParser::parseOptimize() {
//     accept(Token::OPTIMIZE);
//     accept(Token::TABLE);

//     MySqlOptimizeStatement* stmt = new MySqlOptimizeStatement*();
//     std::list<SQLName_ptr > names = new Arraystd::list<SQLName_ptr >();
//     this->exprParser->names(names, stmt);

//     for (SQLName_ptr  name : names) {
//         stmt->addTableSource(new SQLExprTableSource(name));
//     }
//     return stmt;
// }

SQLStatement_ptr MySqlStatementParser::parseReset()
{
  acceptIdentifier(RESET);

  // MySqlResetStatement* stmt = new MySqlResetStatement();

  // for (; ; ) {
  //     if (lexer->token()->name->c_str() == Token::IDENTIFIER.name->c_str()) {
  //         if (lexer->identifierEquals(make_string_ptr("QUERY"))) {
  //             lexer->nextToken();
  //             accept(Token::CACHE);
  //             stmt->getOptions().add("QUERY CACHE");
  //         } else {
  //             stmt->getOptions().add(lexer->stringVal());
  //             lexer->nextToken();
  //         }

  //         if (lexer->token()->name->c_str() == Token::COMMA.name->c_str()) {
  //             lexer->nextToken();
  //             continue;
  //         }
  //     }
  //     break;
  // }

  // return stmt;
  return nullptr;
}

BOOL_ptr MySqlStatementParser::parseStatementListDialect(SQLStatement_list_ptr statementList)
{
  LOG_INFO << "lexer text:" << lexer->stringVal()->c_str();
  LOG_INFO << "token name:" << lexer->token()->getName()->c_str();
  if (lexer->identifierEquals(L"PREPARE"))
  {
    // MySqlPrepareStatement* stmt = parsePrepare();
    // statementList->push_back(stmt);
    // return BOOL::TRUE;
  }

  if (lexer->identifierEquals(L"EXECUTE"))
  {
    acceptIdentifier("EXECUTE");

    if (lexer->identifierEquals(L"RESTART") ||
        lexer->identifierEquals(L"UPDATE"))
    {
      // MySqlExecuteForAdsStatement* stmt = parseExecuteForAds();
      // statementList->push_back(stmt);
    }
    else
    {
      // MySqlExecuteStatement* stmt = parseExecute();
      // statementList->push_back(stmt);
    }
    return BOOL::TRUE;
  }

  if (lexer->identifierEquals(L"DEALLOCATE"))
  {
    // MysqlDeallocatePrepareStatement* stmt = parseDeallocatePrepare();
    // statementList->push_back(stmt);
    // return BOOL::TRUE;
  }

  if (lexer->identifierEquals(L"LOAD"))
  {
    SQLStatement_ptr stmt = parseLoad();
    statementList->push_back(stmt);
    return BOOL::TRUE;
  }

  if (lexer->token()->name->c_str() == Token::REPLACE.name->c_str())
  {
    // SQLReplaceStatement* stmt = parseReplace();
    // statementList->push_back(stmt);
    return BOOL::TRUE;
  }

  if (lexer->identifierEquals(L"START"))
  {
    // SQLStartTransactionStatement* stmt = parseStart();
    // statementList->push_back(stmt);
    return BOOL::TRUE;
  }

  if (lexer->token()->name->c_str() == Token::SHOW.name->c_str())
  {
    SQLStatement_ptr stmt = parseShow();
    statementList->push_back(stmt);
    return BOOL::TRUE;
  }

  if (lexer->identifierEquals(L"CLEAR"))
  {
    lexer->nextToken();

    if (isEnabled(SQLParserFeature_ptr(new SQLParserFeature(&SQLParserFeature::DRDSAsyncDDL))) &&
        lexer->identifierEquals(L"DDL"))
    {
      // CLEAR DDL CACHE { ALL | <job_id> [ , <job_id> ] ... }
      lexer->nextToken();
      accept(Token::CACHE);

      // DrdsClearDDLJobCache* stmt = new DrdsClearDDLJobCache();
      if (Token::ALL.name->c_str() == lexer->token()->name->c_str())
      {
        lexer->nextToken();
        // stmt->setAllJobs(BOOL::TRUE);
        // statementList->push_back(stmt);
        return BOOL::TRUE;
      }
      else
      {
        while (BOOL::TRUE)
        {
          // stmt->addJobId(lexer->integerValue());
          accept(Token::LITERAL_INT);
          if (Token::COMMA == *lexer->token())
          {
            lexer->nextToken();
          }
          else if (lexer->token()->name->c_str() == Token::XEOF.name->c_str() ||
                   lexer->token()->name->c_str() == Token::SEMI.name->c_str())
          {
            break;
          }
          else
          {
            throw new ParserException(make_string_ptr("syntax error, expect job id, actual " + *(lexer->token()->getName()) + ", " + encode_util::UnicodeToUTF8(lexer->info())));
          }
        }
        // statementList->push_back(stmt);
        return BOOL::TRUE;
      }
    }

    acceptIdentifier("PLANCACHE");

    // statementList->push_back(new MySqlClearPlanCacheStatement());
    return BOOL::TRUE;
  }

  if (lexer->identifierEquals(L"DISABLED"))
  {
    lexer->nextToken();
    acceptIdentifier("PLANCACHE");

    // statementList->push_back(new MySqlDisabledPlanCacheStatement());
    return BOOL::TRUE;
  }

  if (lexer->identifierEquals(L"XA"))
  {
    lexer->nextToken();
    // MySqlXAStatement* stmt = new MySqlXAStatement();
    string_ptr typeStr = make_string_ptr(encode_util::UnicodeToUTF8(*lexer->stringVal()));
    // stmt->setType(MySqlXAStatement.XAType.of(typeStr));
    lexer->nextToken();

    if (lexer->token()->name->c_str() != Token::XEOF.name->c_str() &&
        lexer->token()->name->c_str() != Token::SEMI.name->c_str())
    {
      SQLExpr_ptr xid = exprParser->getExpr();
      // stmt->setId(xid);
    }

    // statementList->push_back(stmt);
    return BOOL::TRUE;
  }

  if (lexer->token()->name->c_str() == Token::EXPLAIN.name->c_str())
  {
    // SQLStatement_ptr  stmt = this->parseExplain();
    // statementList->push_back(stmt);
    return BOOL::TRUE;
  }

  if (lexer->identifierEquals(BINLOG))
  {
    SQLStatement_ptr stmt = parseBinlog();
    statementList->push_back(stmt);
    return BOOL::TRUE;
  }

  if (lexer->identifierEquals(RESET))
  {
    SQLStatement_ptr stmt = parseReset();
    statementList->push_back(stmt);
    return BOOL::TRUE;
  }

  if (lexer->token()->name->c_str() == Token::ANALYZE.name->c_str())
  {
    // SQLStatement_ptr  stmt = parseAnalyze();
    // statementList->push_back(stmt);
    return BOOL::TRUE;
  }

  if (lexer->identifierEquals(FnvHash::Constants::ARCHIVE))
  {
    SQLStatement_ptr stmt = parseArchive();
    statementList->push_back(stmt);
    return BOOL::TRUE;
  }

  if (lexer->identifierEquals(FnvHash::Constants::BACKUP))
  {
    SQLStatement_ptr stmt = parseBackup();
    statementList->push_back(stmt);
    return BOOL::TRUE;
  }

  if (lexer->identifierEquals(FnvHash::Constants::RESTORE))
  {
    SQLStatement_ptr stmt = parseRestore();
    statementList->push_back(stmt);
    return BOOL::TRUE;
  }

  if (lexer->identifierEquals(make_string_ptr("BUILD")))
  {
    SQLStatement_ptr stmt = parseBuildTable();
    statementList->push_back(stmt);
    return BOOL::TRUE;
  }

  if (lexer->identifierEquals(make_string_ptr("CANCEL")))
  {
    SQLStatement_ptr stmt = parseCancelJob();
    statementList->push_back(stmt);
    return BOOL::TRUE;
  }

  if (lexer->identifierEquals(FnvHash::Constants::EXPORT))
  {
    lexer->nextToken();
    if (lexer->token()->name->c_str() == Token::TABLE.name->c_str())
    {
      SQLStatement_ptr stmt = parseExportTable();
      statementList->push_back(stmt);
    }
    else if (lexer->token()->name->c_str() == Token::DATABASE.name->c_str())
    {
      SQLStatement_ptr stmt = parseExportDB();
      statementList->push_back(stmt);
    }
    return BOOL::TRUE;
  }

  if (lexer->identifierEquals(FnvHash::Constants::IMPORT))
  {
    lexer->nextToken();
    if (lexer->token()->name->c_str() == Token::TABLE.name->c_str())
    {
      SQLStatement_ptr stmt = parseImportTable();
      statementList->push_back(stmt);
    }
    else if (lexer->token()->name->c_str() == Token::DATABASE.name->c_str())
    {
      SQLStatement_ptr stmt = parseImportDB();
      statementList->push_back(stmt);
    }
    return BOOL::TRUE;
  }

  if (lexer->identifierEquals(make_string_ptr("SUBMIT")))
  {
    lexer->nextToken();
    acceptIdentifier("JOB");

    SQLStatement_ptr stmt = parseSubmitJob();
    statementList->push_back(stmt);
    return BOOL::TRUE;
  }

  if (lexer->identifierEquals(FnvHash::Constants::MIGRATE))
  {
    SQLStatement_ptr stmt = parseMigrate();
    statementList->push_back(stmt);
    return BOOL::TRUE;
  }

  if (lexer->token()->name->c_str() == Token::OPTIMIZE.name->c_str())
  {
    // SQLStatement_ptr  stmt = parseOptimize();
    // statementList->push_back(stmt);
    return BOOL::TRUE;
  }

  if (lexer->identifierEquals(make_string_ptr("HELP")))
  {
    lexer->nextToken();
    // MySqlHelpStatement* stmt = new MySqlHelpStatement();
    // stmt->setContent(this->exprParser->primary());
    // statementList->push_back(stmt);
    return BOOL::TRUE;
  }

  if (lexer->identifierEquals(make_string_ptr("FLUSH")))
  {
    SQLStatement_ptr stmt = parseFlush();
    statementList->push_back(stmt);
    return BOOL::TRUE;
  }

  if (lexer->identifierEquals(FnvHash::Constants::SYNC))
  {
    SQLStatement_ptr stmt = parseSync();
    statementList->push_back(stmt);
    return BOOL::TRUE;
  }

  if (lexer->identifierEquals(FnvHash::Constants::INIT))
  {
    // statementList->push_back(new SQLExprStatement(this->exprParser->getExpr()));
    return BOOL::TRUE;
  }

  // DRDS async DDL.
  if (isEnabled(SQLParserFeature_ptr(new SQLParserFeature(&SQLParserFeature::DRDSAsyncDDL))) &&
      lexer->identifierEquals(FnvHash::Constants::RECOVER))
  {
    // RECOVER DDL {ALL | <job_id> [, <job_id>] ...}
    lexer->nextToken();
    acceptIdentifier("DDL");
    // DrdsRecoverDDLJob* stmt = new DrdsRecoverDDLJob();
    if (Token::ALL.name->c_str() == lexer->token()->name->c_str())
    {
      lexer->nextToken();
      // stmt->setAllJobs(BOOL::TRUE);
      // statementList->push_back(stmt);
      return BOOL::TRUE;
    }
    else
    {
      while (BOOL::TRUE)
      {
        // stmt->addJobId(lexer->integerValue().longValue());
        accept(Token::LITERAL_INT);
        if (Token::COMMA == *lexer->token())
        {
          lexer->nextToken();
        }
        else if (lexer->token()->name->c_str() == Token::XEOF.name->c_str() ||
                 lexer->token()->name->c_str() == Token::SEMI.name->c_str())
        {
          break;
        }
        else
        {
          throw new ParserException(make_string_ptr("syntax error, expect job id, actual " + *lexer->token()->getName() + ", " + encode_util::UnicodeToUTF8(lexer->info())));
        }
      }
      // statementList->push_back(stmt);
      return BOOL::TRUE;
    }
  }

  if (isEnabled(SQLParserFeature_ptr(new SQLParserFeature(&SQLParserFeature::DRDSAsyncDDL))) &&
      lexer->identifierEquals(FnvHash::Constants::REMOVE))
  {
    // REMOVE DDL { ALL { COMPLETED | PENDING } | <job_id> [, <job_id>] ...}
    lexer->nextToken();
    acceptIdentifier("DDL");
    // DrdsRemoveDDLJob stmt = new DrdsRemoveDDLJob();
    if (Token::ALL == *lexer->token())
    {
      lexer->nextToken();
      if (lexer->identifierEquals(make_string_ptr("COMPLETED")))
      {
        lexer->nextToken();
        // stmt->setAllCompleted(BOOL::TRUE);
      }
      else if (lexer->identifierEquals(make_string_ptr("PENDING")))
      {
        lexer->nextToken();
        // stmt->setAllPending(BOOL::TRUE);
      }
      else
      {
        throw new ParserException(make_string_ptr("syntax error, expect COMPLETED or PENDING, actual " + *lexer->token()->getName() + ", " + encode_util::UnicodeToUTF8(lexer->info())));
      }
    }
    else
    {
      while (BOOL::TRUE)
      {
        // stmt->addJobId(lexer->integerValue().longValue());
        accept(Token::LITERAL_INT);
        if (Token::COMMA == *lexer->token())
        {
          lexer->nextToken();
        }
        else if (lexer->token()->name->c_str() == Token::XEOF.name->c_str() || lexer->token()->name->c_str() == Token::SEMI.name->c_str())
        {
          break;
        }
        else
        {
          throw new ParserException(make_string_ptr("syntax error, expect job id, actual " + *lexer->token()->getName() + ", " + encode_util::UnicodeToUTF8(lexer->info())));
        }
      }
    }
    // statementList->push_back(stmt);
    return BOOL::TRUE;
  }

  if (isEnabled(SQLParserFeature_ptr(new SQLParserFeature(&SQLParserFeature::DRDSAsyncDDL))) &&
      lexer->identifierEquals(make_string_ptr("INSPECT")))
  {
    // INSPECT DDL CACHE
    lexer->nextToken();
    acceptIdentifier("DDL");
    accept(Token::CACHE);
    // statementList->push_back(new DrdsInspectDDLJobCache());
    return BOOL::TRUE;
  }

  if (isEnabled(SQLParserFeature_ptr(new SQLParserFeature(&SQLParserFeature::DRDSAsyncDDL))) &&
      lexer->identifierEquals(FnvHash::Constants::CHANGE))
  {
    // CHANGE DDL <job_id> { SKIP | ADD } <group_and_table_name> [ , <group_and_table_name> ] ...
    Lexer_SavePoint_ptr mark = lexer->mark();
    lexer->nextToken();
    if (lexer->identifierEquals(make_string_ptr("DDL")))
    {
      lexer->nextToken();

      // DrdsChangeDDLJob* stmt = new DrdsChangeDDLJob();

      // stmt->setJobId(lexer->integerValue().longValue());
      accept(Token::LITERAL_INT);

      if (lexer->identifierEquals(make_string_ptr("SKIP")))
      {
        lexer->nextToken();
        // stmt->setSkip(BOOL::TRUE);
      }
      else if (lexer->identifierEquals(make_string_ptr("ADD")))
      {
        lexer->nextToken();
        // stmt->setAdd(BOOL::TRUE);
      }
      else
      {
        throw new ParserException(make_string_ptr("syntax error, expect SKIP or ADD, actual " + *lexer->token()->getName() + ", " + encode_util::UnicodeToUTF8(lexer->info())));
      }

      string_ptr builder = make_string_ptr("");
      while (BOOL::TRUE)
      {
        if (Token::COMMA == *lexer->token())
        {
          lexer->nextToken();
          // stmt->addGroupAndTableNamestd::list(builder.toString());
          builder->clear();
        }
        else if (lexer->token()->name->c_str() == Token::XEOF.name->c_str() ||
                 lexer->token()->name->c_str() == Token::SEMI.name->c_str())
        {
          // stmt->addGroupAndTableNamestd::list(builder.toString());
          break;
        }
        else if (lexer->token()->name->c_str() == Token::COLON.name->c_str())
        {
          builder->append(":");
          lexer->nextToken();
        }
        else if (lexer->token()->name->c_str() == Token::DOT.name->c_str())
        {
          builder->append(".");
          lexer->nextToken();
        }
        else
        {
          builder->append(encode_util::UnicodeToUTF8(*lexer->stringVal()));
          lexer->nextToken();
        }
      }

      // statementList->push_back(stmt);
      return BOOL::TRUE;
    }
    lexer->reset(mark);
  }

  if (isEnabled(SQLParserFeature_ptr(new SQLParserFeature(&SQLParserFeature::DRDSBaseline))) &&
      lexer->identifierEquals(make_string_ptr("BASELINE")))
  {
    lexer->nextToken();

    // DrdsBaselineStatement* stmt = new DrdsBaselineStatement();

    if (Token::XEOF == *lexer->token() ||
        Token::SEMI == *lexer->token() ||
        lexer->stringVal()->empty() ||
        StringUtils::iequals(encode_util::UnicodeToUTF8(lexer->stringVal()->c_str()), "BASELINE"))
    {
      throw new ParserException(make_string_ptr("syntax error, expect baseline operation, actual " + *lexer->token()->getName() + ", " + encode_util::UnicodeToUTF8(lexer->info())));
    }

    // stmt->setOperation(lexer->stringVal());

    lexer->setToken(Token_ptr(new Token(&Token::COMMA))); // Hack here: Set previous comma to deal with negative number.
    lexer->nextToken();

    if (lexer->identifierEquals(FnvHash::Constants::SQL))
    {
      // Parse select.
      lexer->nextToken();

      if (lexer->token()->name->c_str() == Token::HINT.name->c_str())
      {
        // stmt->setHeadHints(this->exprParser->parseHints());
      }

      // MySqlSelectParser* selectParser = createSQLSelectParser();
      // stmt->setSelect(selectParser.select());
    }
    else
    {
      // Parse id list.
      while (lexer->token()->name->c_str() != Token::XEOF.name->c_str() &&
             lexer->token()->name->c_str() != Token::SEMI.name->c_str())
      {
        // stmt->addBaselineId(lexer->integerValue().longValue());
        accept(Token::LITERAL_INT);
        if (Token::COMMA == *lexer->token())
        {
          lexer->nextToken();
        }
      }
    }

    // statementList->push_back(stmt);
    return BOOL::TRUE;
  }

  if (lexer->token()->name->c_str() == Token::DESC.name->c_str() ||
      lexer->identifierEquals(DESCRIBE))
  {
    // SQLStatement_ptr  stmt = parseDescribe();
    // statementList->push_back(stmt);
    return BOOL::TRUE;
  }

  if (lexer->token()->name->c_str() == Token::LOCK.name->c_str())
  {
    lexer->nextToken();
    string_ptr val = make_string_ptr(encode_util::UnicodeToUTF8(*lexer->stringVal()));
    BOOL_ptr isLockTables = (StringUtils::iequals(*TABLES, *val) &&
                             lexer->token()->name->c_str() == Token::IDENTIFIER.name->c_str())
                                ? BOOL::TRUE
                                : BOOL::FALSE;
    BOOL_ptr isLockTable = (StringUtils::iequals("TABLE", *val) &&
                            lexer->token()->name->c_str() == Token::TABLE.name->c_str())
                               ? BOOL::TRUE
                               : BOOL::FALSE;
    if (isLockTables || isLockTable)
    {
      lexer->nextToken();
    }
    else
    {
      setErrorEndPos(lexer->pos());
      throw new ParserException(make_string_ptr("syntax error, expect TABLES or TABLE, actual " + *lexer->token()->getName() + ", " + encode_util::UnicodeToUTF8(lexer->info())));
    }

    // MySqlLockTableStatement stmt = new MySqlLockTableStatement();

    for (;;)
    {
      // MySqlLockTableStatement.Item item = new MySqlLockTableStatement.Item();

      SQLExprTableSource_ptr tableSource = nullptr;
      SQLName_ptr tableName = this->exprParser->name();

      if (lexer->token()->name->c_str() == Token::AS.name->c_str())
      {
        lexer->nextToken();
        string_ptr as = make_string_ptr(encode_util::UnicodeToUTF8(*lexer->stringVal()));
        tableSource = SQLExprTableSource_ptr(new SQLExprTableSource(tableName, as));
        lexer->nextToken();
      }
      else
      {
        tableSource = SQLExprTableSource_ptr(new SQLExprTableSource(tableName));
      }
      // item->setTableSource(tableSource);
      // stmt->getItems().add(item);

      if (lexer->token()->name->c_str() == Token::COMMA.name->c_str())
      {
        lexer->nextToken();
        continue;
      }

      if (lexer->identifierEquals(READ))
      {
        lexer->nextToken();
        if (lexer->identifierEquals(LOCAL))
        {
          lexer->nextToken();
          // item.setLockType(LockType.READ_LOCAL);
        }
        else
        {
          // item.setLockType(LockType.READ);
        }
      }
      else if (lexer->identifierEquals(WRITE))
      {
        lexer->nextToken();
        // item.setLockType(LockType.WRITE);
      }
      else if (lexer->identifierEquals(FnvHash::Constants::LOW_PRIORITY))
      {
        lexer->nextToken();
        acceptIdentifier(WRITE);
        lexer->nextToken();
        // item.setLockType(LockType.LOW_PRIORITY_WRITE);
      }
      else
      {
        throw new ParserException(make_string_ptr("syntax error, expect READ or WRITE OR AS, actual " + *lexer->token()->getName() + ", " + encode_util::UnicodeToUTF8(lexer->info())));
      }

      if (lexer->token()->name->c_str() == Token::HINT.name->c_str())
      {
        // item.setHints(this->exprParser->parseHints());
      }

      if (lexer->token()->name->c_str() == Token::COMMA.name->c_str())
      {
        lexer->nextToken();
        continue;
      }
      break;
    }

    // statementList->push_back(stmt);
    return BOOL::TRUE;
  }

  if (lexer->identifierEquals(make_string_ptr("UNLOCK")))
  {
    lexer->nextToken();
    string_ptr val = make_string_ptr(encode_util::UnicodeToUTF8(*lexer->stringVal()));
    BOOL_ptr isUnLockTables = (StringUtils::iequals(*TABLES, *val) && lexer->token()->name->c_str() == Token::IDENTIFIER.name->c_str()) ? BOOL::TRUE : BOOL::FALSE;
    BOOL_ptr isUnLockTable = (StringUtils::iequals("TABLE", *val) && lexer->token()->name->c_str() == Token::TABLE.name->c_str()) ? BOOL::TRUE : BOOL::FALSE;
    // statementList->push_back(new MySqlUnlockTablesStatement());
    if (isUnLockTables || isUnLockTable)
    {
      lexer->nextToken();
    }
    else
    {
      setErrorEndPos(lexer->pos());
      throw new ParserException(make_string_ptr("syntax error, expect TABLES or TABLE, actual " + *lexer->token()->getName() + ", " + encode_util::UnicodeToUTF8(lexer->info())));
    }
    return BOOL::TRUE;
  }

  if (lexer->identifierEquals(FnvHash::Constants::CHECKSUM))
  {
    // statementList->push_back(this->parseChecksum());
    return BOOL::TRUE;
  }

  if (lexer->token()->name->c_str() == Token::HINT.name->c_str())
  {
    // std::list<SQLCommentHint*> hints = this->exprParser->parseHints();

    BOOL_ptr tddlHints = BOOL::FALSE;
    BOOL_ptr accept = BOOL::FALSE;

    BOOL_ptr acceptHint = BOOL::FALSE;

    if (lexer->token()->name->c_str() == Token::SELECT.name->c_str() ||
        lexer->token()->name->c_str() == Token::WITH.name->c_str() ||
        lexer->token()->name->c_str() == Token::DELETE.name->c_str() ||
        lexer->token()->name->c_str() == Token::UPDATE.name->c_str() ||
        lexer->token()->name->c_str() == Token::INSERT.name->c_str() ||
        lexer->token()->name->c_str() == Token::SHOW.name->c_str() ||
        lexer->token()->name->c_str() == Token::REPLACE.name->c_str() ||
        lexer->token()->name->c_str() == Token::TRUNCATE.name->c_str() ||
        lexer->token()->name->c_str() == Token::DROP.name->c_str() ||
        lexer->token()->name->c_str() == Token::ALTER.name->c_str() ||
        lexer->token()->name->c_str() == Token::CREATE.name->c_str() ||
        lexer->token()->name->c_str() == Token::CHECK.name->c_str() ||
        lexer->token()->name->c_str() == Token::SET.name->c_str() ||
        lexer->token()->name->c_str() == Token::DESC.name->c_str() ||
        lexer->token()->name->c_str() == Token::OPTIMIZE.name->c_str() ||
        lexer->token()->name->c_str() == Token::ANALYZE.name->c_str() ||
        lexer->token()->name->c_str() == Token::KILL.name->c_str() ||
        lexer->token()->name->c_str() == Token::EXPLAIN.name->c_str() ||
        lexer->token()->name->c_str() == Token::LPAREN.name->c_str())
    {
      acceptHint = BOOL::TRUE;
    }
    else if (lexer->token()->name->c_str() == Token::IDENTIFIER.name->c_str())
    {
      acceptHint = (lexer->hashLCase() == FnvHash::Constants::DUMP ||
                    lexer->hashLCase() == FnvHash::Constants::RENAME ||
                    lexer->hashLCase() == FnvHash::Constants::DESCRIBE)
                       ? BOOL::TRUE
                       : BOOL::FALSE;
    }
    // if (hints.size() >= 1
    //         && statementList->empty()
    //         && acceptHint) {
    //     SQLCommentHint* hint = hints.get(0);
    //     string_ptr  hintText = hint.getText().toUpperCase();
    //     if (hintText.startsWith("+TDDL")
    //             || hintText.startsWith("+ TDDL")
    //             || hintText.startsWith("TDDL")
    //             || hintText.startsWith("!TDDL")) {
    //         tddlHints = BOOL::TRUE;
    //     } else if (hintText.startsWith("+")) {
    //         accept = BOOL::TRUE;
    //     }
    // }

    if (tddlHints)
    {
      // SQLStatementImpl* stmt = (SQLStatementImpl) this->parseStatement();
      // stmt->setHeadHints(hints);
      // statementList->push_back(stmt);
      return BOOL::TRUE;
    }
    else if (accept)
    {
      // SQLStatementImpl stmt = (SQLStatementImpl) this->parseStatement();
      // stmt->setHeadHints(hints);
      // statementList->push_back(stmt);
      return BOOL::TRUE;
    }

    // MySqlHintStatement stmt = new MySqlHintStatement();
    // stmt->setHints(hints);

    // statementList->push_back(stmt);
    return BOOL::TRUE;
  }

  if (lexer->token()->name->c_str() == Token::BEGIN.name->c_str())
  {
    // Lexer::SavePoint mark = lexer->mark();
    lexer->nextToken();
    if (lexer->token()->name->c_str() == Token::SEMI.name->c_str() ||
        lexer->token()->name->c_str() == Token::XEOF.name->c_str() ||
        lexer->token()->name->c_str() == Token::IDENTIFIER.name->c_str())
    {
      // lexer->reset(mark);
      // statementList->push_back(this->parseTiDBBeginStatment());
      return BOOL::TRUE;
    }
    else
    {
      // lexer->reset(mark);
    }
    // statementList->push_back(this->parseBlock());
    return BOOL::TRUE;
  }

  if (lexer->identifierEquals(FnvHash::Constants::ADD))
  {
    statementList->push_back(parseAddManageInstanceGroup());
    return BOOL::TRUE;
  }

  if (lexer->token()->name->c_str() == Token::IDENTIFIER.name->c_str())
  {
    string_ptr label = make_string_ptr(encode_util::UnicodeToUTF8(*lexer->stringVal()));
    Lexer_SavePoint_ptr savePoint = lexer->markOut();
    LOG_INFO << "token name:" << lexer->token()->getName()->c_str();
    lexer->nextToken();

    LOG_INFO << "lexer text:" << lexer->stringVal()->c_str();
    LOG_INFO << "token name:" << lexer->token()->getName()->c_str();

    if (lexer->token()->name->c_str() == Token::VARIANT.name->c_str() &&
        encode_util::UnicodeToUTF8(*lexer->stringVal()) == ":")
    {
      lexer->nextToken();
      if (lexer->token()->name->c_str() == Token::LOOP.name->c_str())
      {
        // parse loop statement
        statementList->push_back(this->parseLoop(label));
      }
      else if (lexer->token()->name->c_str() == Token::WHILE.name->c_str())
      {
        // parse while statement with label
        statementList->push_back(this->parseWhile(label));
      }
      else if (lexer->token()->name->c_str() == Token::BEGIN.name->c_str())
      {
        // parse begin-end statement with label
        SQLBlockStatement_ptr block = std::dynamic_pointer_cast<SQLBlockStatement>(this->parseBlock(label));
        statementList->push_back(block);
      }
      else if (lexer->token()->name->c_str() == Token::REPEAT.name->c_str())
      {
        // parse repeat statement with label
        statementList->push_back(std::dynamic_pointer_cast<SQLStatement>(this->parseRepeat(label)));
      }
      return BOOL::TRUE;
    }
    else
    {
      lexer->reset(savePoint);
    }
  }

  if (lexer->token()->name->c_str() == Token::CHECK.name->c_str())
  {
    // Lexer::SavePoint mark = lexer->mark();
    lexer->nextToken();

    if (lexer->token()->name->c_str() == Token::TABLE.name->c_str())
    {
      lexer->nextToken();

      // MySqlCheckTableStatement stmt = new MySqlCheckTableStatement();
      for (;;)
      {
        // SQLName_ptr  table = this->exprParser->name();
        // stmt->addTable(new SQLExprTableSource(table));

        if (lexer->token()->name->c_str() == Token::COMMA.name->c_str())
        {
          lexer->nextToken();
          continue;
        }

        break;
      }
      // statementList->push_back(stmt);
    }
    return BOOL::TRUE;
  }

  LOG_INFO << "return BOOL::FALSE";
  return BOOL::FALSE;
}

SQLStatement_ptr MySqlStatementParser::parseArchive()
{
  lexer->nextToken();
  accept(Token::TABLE);
  // SQLArchiveTableStatement stmt = new SQLArchiveTableStatement();

  // SQLName_ptr  tableName = this->exprParser->name();
  // stmt->setTable(tableName);
  // stmt->setType(new SQLIdentifierExpr("UPLOAD"));

  if (lexer->token()->name->c_str() == Token::LITERAL_INT.name->c_str())
  {
    for (;;)
    {
      // stmt->getSpIdstd::list().add(this->exprParser->integerExpr());
      string_ptr pidStr = make_string_ptr(encode_util::UnicodeToUTF8(*lexer->stringVal()));
      accept(Token::VARIANT);
      // string_ptr  s = pidStr.replaceAll(":", "");
      string_ptr s = pidStr;
      // boost::algorithm::replace_all(s, ":", "");
      s = StringUtils::replaceAll(s, make_string_ptr(":"), make_string_ptr(""));
      // if (StringUtils::isEmpty(s)) {
      if (s->empty())
      {
        // stmt->getpIdList().add(exprParser->integerExpr());
      }
      else
      {
        // stmt->getpIdList().add(new SQLIntegerExpr(Integer.valueOf(s)));
      }

      if (lexer->token()->name->c_str() == Token::COMMA.name->c_str())
      {
        lexer->nextToken();
        continue;
      }

      break;
    }
  }
  // return stmt;
  return nullptr;
}

SQLStatement_ptr MySqlStatementParser::parseBackup()
{
  lexer->nextToken();
  // SQLBackupStatement* stmt = new SQLBackupStatement();

  string_ptr type = make_string_ptr("BACKUP_DATA");
  string_ptr action = make_string_ptr("BACKUP");

  if (lexer->identifierEquals(FnvHash::Constants::DATA))
  {
    lexer->nextToken();
    accept(Token::INTO);
    type = make_string_ptr("BACKUP_DATA");

    for (;;)
    {
      // stmt->getProperties().add(new SQLCharExpr(lexer->stringVal()));
      accept(Token::LITERAL_CHARS);
      if (lexer->token()->name->c_str() == Token::COMMA.name->c_str())
      {
        lexer->nextToken();
        continue;
      }
      break;
    }
  }
  else if (lexer->identifierEquals(FnvHash::Constants::LOG))
  {
    type = make_string_ptr("BACKUP_LOG");
    lexer->nextToken();

    if (lexer->identifierEquals(make_string_ptr("LIST_LOGS")))
    {
      lexer->nextToken();
      action = make_string_ptr("LIST_LOG");
    }
    else if (lexer->identifierEquals(FnvHash::Constants::STATUS))
    {
      lexer->nextToken();
      action = make_string_ptr("STATUS");
    }
    else if (lexer->token()->name->c_str() == Token::INTO.name->c_str())
    {
      lexer->nextToken();
      for (;;)
      {
        // stmt->getProperties().add(new SQLCharExpr(lexer->stringVal()));
        accept(Token::LITERAL_CHARS);
        if (lexer->token()->name->c_str() == Token::COMMA.name->c_str())
        {
          lexer->nextToken();
          continue;
        }
        break;
      }
    }
  }
  else if (lexer->identifierEquals(make_string_ptr("CANCEL")))
  {
    lexer->nextToken();
    type = make_string_ptr("BACKUP_DATA");
    action = make_string_ptr("BACKUP_CANCEL");
    // stmt->getProperties().add(new SQLCharExpr(lexer->stringVal()));
    accept(Token::LITERAL_CHARS);
  }

  // stmt->setType(new SQLIdentifierExpr(type));
  // stmt->setAction(new SQLIdentifierExpr(action));

  // return stmt;
  return nullptr;
}

SQLStatement_ptr MySqlStatementParser::parseRestore()
{
  lexer->nextToken();

  string_ptr type = make_string_ptr("DATA");

  // SQLRestoreStatement* stmt = new SQLRestoreStatement();

  if (lexer->identifierEquals(FnvHash::Constants::DATA))
  {
    lexer->nextToken();
    type = make_string_ptr("DATA");
  }
  else if (lexer->identifierEquals(FnvHash::Constants::LOG))
  {
    lexer->nextToken();
    type = make_string_ptr("LOG");
  }

  // stmt->setType(new SQLIdentifierExpr(type));

  accept(Token::FROM);
  for (;;)
  {
    // stmt->getProperties().add(new SQLCharExpr(lexer->stringVal()));
    accept(Token::LITERAL_CHARS);
    if (lexer->token()->name->c_str() == Token::COMMA.name->c_str())
    {
      lexer->nextToken();
      continue;
    }
    break;
  }
  // return stmt;
  return nullptr;
}

SQLStatement_ptr MySqlStatementParser::parseBuildTable()
{
  lexer->nextToken();

  // SQLBuildTableStatement* stmt = new SQLBuildTableStatement();

  accept(Token::TABLE);

  // stmt->setTable(this->exprParser->name());

  if (lexer->identifierEquals(FnvHash::Constants::VERSION))
  {
    lexer->nextToken();
    accept(Token::EQ);
    // stmt->setVersion(this->exprParser->integerExpr());
  }

  if (lexer->token()->name->c_str() == Token::WITH.name->c_str())
  {
    lexer->nextToken();
    acceptIdentifier("SPLIT");

    // stmt->setWithSplit(BOOL::TRUE);
  }

  if (lexer->identifierEquals(FnvHash::Constants::FORCE))
  {
    lexer->nextToken();

    accept(Token::EQ);

    if (lexer->token()->name->c_str() == Token::XTRUE.name->c_str())
    {
      lexer->nextToken();
      // stmt->setForce(BOOL::TRUE);
    }
    else if (lexer->token()->name->c_str() == Token::XFALSE.name->c_str())
    {
      lexer->nextToken();
      // stmt->setForce(BOOL::FALSE);
    }
  }

  // return stmt;
  return nullptr;
}

SQLStatement_ptr MySqlStatementParser::parseCancelJob()
{
  lexer->nextToken();

  // DRDS async DDL.
  if (isEnabled(SQLParserFeature_ptr(new SQLParserFeature(&SQLParserFeature::DRDSAsyncDDL))) &&
      lexer->identifierEquals(make_string_ptr("DDL")))
  {
    // CANCEL DDL <job_id> [, <job_id>] ...
    lexer->nextToken();
    // DrdsCancelDDLJob* cancelDDLJob = new DrdsCancelDDLJob();
    while (BOOL::TRUE)
    {
      // cancelDDLJob.addJobId(lexer->integerValue().longValue());
      accept(Token::LITERAL_INT);
      if (Token::COMMA == *lexer->token())
      {
        lexer->nextToken();
      }
      else if (lexer->token()->name->c_str() == Token::XEOF.name->c_str() ||
               lexer->token()->name->c_str() == Token::SEMI.name->c_str())
      {
        break;
      }
      else
      {
        throw new ParserException(make_string_ptr("syntax error, expect job id, actual " + *lexer->token()->getName() + ", " + encode_util::UnicodeToUTF8(lexer->info())));
      }
    }
    // return cancelDDLJob;
  }

  // SQLCancelJobStatement stmt = new SQLCancelJobStatement();

  if (lexer->identifierEquals(make_string_ptr("JOB")))
  {
    lexer->nextToken();
  }
  else if (lexer->identifierEquals(make_string_ptr("LOAD_JOB")))
  {
    lexer->nextToken();
  }
  else if (lexer->identifierEquals(make_string_ptr("SYNC_JOB")))
  {
    lexer->nextToken();
    // stmt->setImport(BOOL::TRUE);
  }

  // stmt->setJobName(this->exprParser->name());

  // return stmt;
  return nullptr;
}

SQLStatement_ptr MySqlStatementParser::parseExportTable()
{
  accept(Token::TABLE);
  // SQLExportTableStatement stmt = new SQLExportTableStatement();
  // stmt->setTable(new SQLExprTableSource(this->exprParser->name()));
  // return stmt;
  return nullptr;
}

SQLStatement_ptr MySqlStatementParser::parseExportDB()
{
  accept(Token::DATABASE);
  // SQLExportDatabaseStatement stmt = new SQLExportDatabaseStatement();
  // stmt->setDb(this->exprParser->name());

  if (lexer->identifierEquals(make_string_ptr("REALTIME")))
  {
    lexer->nextToken();
    accept(Token::EQ);
    if (StringUtils::iequals("y", encode_util::UnicodeToUTF8(lexer->stringVal()->c_str())))
    {
      lexer->nextToken();
      // stmt->setRealtime(BOOL::TRUE);
    }
    else if (StringUtils::iequals("n", encode_util::UnicodeToUTF8(lexer->stringVal()->c_str())))
    {
      lexer->nextToken();
      // stmt->setRealtime(BOOL::FALSE);
    }
    else
    {
      throw new ParserException(make_string_ptr("Invalid 'realtime' option, should be 'Y' or 'N'. "));
    }
  }

  // return stmt;
  return nullptr;
}

SQLStatement_ptr MySqlStatementParser::parseRaftLeaderTransfer()
{
  acceptIdentifier("RAFT_LEADER_TRANSFER");
  // MySqlRaftLeaderTransferStatement stmt = new MySqlRaftLeaderTransferStatement();

  acceptIdentifier("SHARD");
  accept(Token::EQ);

  // stmt->setShard(exprParser->charExpr());

  accept(Token::FROM);
  accept(Token::EQ);
  // stmt->setFrom(exprParser->charExpr());

  accept(Token::TO);
  accept(Token::EQ);
  // stmt->setTo(exprParser->charExpr());

  acceptIdentifier("TIMEOUT");
  accept(Token::EQ);
  // stmt->setTimeout(exprParser->integerExpr());

  // return stmt;
  return nullptr;
}

SQLStatement_ptr MySqlStatementParser::parseRaftMemeberChange()
{
  acceptIdentifier("RAFT_MEMBER_CHANGE");
  // MySqlRaftMemberChangeStatement stmt = new MySqlRaftMemberChangeStatement();

  if (lexer->identifierEquals(make_string_ptr("NOLEADER")))
  {
    lexer->nextToken();
    // stmt->setNoLeader(BOOL::TRUE);
  }

  acceptIdentifier("SHARD");
  accept(Token::EQ);

  // stmt->setShard(exprParser->charExpr());

  acceptIdentifier("HOST");
  accept(Token::EQ);
  // stmt->setHost(exprParser->charExpr());

  acceptIdentifier("STATUS");
  accept(Token::EQ);
  // stmt->setStatus(exprParser->charExpr());

  if (lexer->identifierEquals(FnvHash::Constants::FORCE))
  {
    lexer->nextToken();
    // stmt->setForce(BOOL::TRUE);
  }

  // return stmt;
  return nullptr;
}

SQLStatement_ptr MySqlStatementParser::parseMigrate()
{
  // MySqlMigrateStatement stmt = new MySqlMigrateStatement();
  acceptIdentifier("MIGRATE");
  accept(Token::DATABASE);

  // stmt->setSchema(exprParser->name());

  acceptIdentifier("SHARDS");
  accept(Token::EQ);
  // stmt->setShardNames(exprParser->charExpr());

  if (lexer->token()->name->c_str() == Token::GROUP.name->c_str())
  {
    lexer->nextToken();
    // stmt->setMigrateType(new SQLIntegerExpr(0));
  }
  else if (lexer->identifierEquals(FnvHash::Constants::HOST))
  {
    lexer->nextToken();
    // stmt->setMigrateType(new SQLIntegerExpr(1));
  }

  accept(Token::FROM);
  // stmt->setFromInsId(exprParser->charExpr());

  if (lexer->token()->name->c_str() == Token::VARIANT.name->c_str())
  {
    lexer->nextToken();
    // stmt->setFromInsIp(exprParser->charExpr());

    string_ptr variant = make_string_ptr(encode_util::UnicodeToUTF8(*lexer->stringVal()));
    // Integer number = Integer.valueOf(variant.substring(1, variant.length()));
    // stmt->setFromInsPort(new SQLIntegerExpr(number));
    accept(Token::VARIANT);

    accept(Token::VARIANT);
    // stmt->setFromInsStatus(exprParser->charExpr());
  }

  accept(Token::TO);
  // stmt->setToInsId(exprParser->charExpr());

  if (lexer->token()->name->c_str() == Token::VARIANT.name->c_str())
  {
    lexer->nextToken();
    // stmt->setToInsIp(exprParser->charExpr());

    string_ptr variant = make_string_ptr(encode_util::UnicodeToUTF8(*lexer->stringVal()));
    // Integer number = Integer.valueOf(variant.substring(1, variant.length()));
    // stmt->setToInsPort(new SQLIntegerExpr(number));
    accept(Token::VARIANT);

    accept(Token::VARIANT);
    // stmt->setToInsStatus(exprParser->charExpr());
  }

  // return stmt;
  return nullptr;
}

SQLStatement_ptr MySqlStatementParser::parseImportDB()
{
  accept(Token::DATABASE);
  // SQLImportDatabaseStatement stmt = new SQLImportDatabaseStatement();

  // stmt->setDb(this->exprParser->name());

  if (lexer->identifierEquals(FnvHash::Constants::STATUS))
  {
    lexer->nextToken();
    accept(Token::EQ);
    // stmt->setStatus(this->exprParser->name());
  }

  // return stmt;
  return nullptr;
}

SQLStatement_ptr MySqlStatementParser::parseImportTable()
{
  // SQLImportTableStatement stmt = new SQLImportTableStatement();
  if (lexer->identifierEquals(FnvHash::Constants::EXTERNAL))
  {
    lexer->nextToken();
    // stmt->setExtenal(BOOL::TRUE);
  }

  accept(Token::TABLE);
  // stmt->setTable(new SQLExprTableSource(this->exprParser->name()));

  acceptIdentifier("VERSION");
  accept(Token::EQ);
  // stmt->setVersion(this->exprParser->integerExpr());

  if (lexer->identifierEquals(make_string_ptr("BUILD")))
  {
    lexer->nextToken();
    accept(Token::EQ);
    if (StringUtils::iequals("Y", encode_util::UnicodeToUTF8(lexer->stringVal()->c_str())))
    {
      lexer->nextToken();
      // stmt->setUsingBuild(BOOL::TRUE);
    }
    else if (StringUtils::iequals("N", encode_util::UnicodeToUTF8(lexer->stringVal()->c_str())))
    {
      lexer->nextToken();
      // stmt->setUsingBuild(BOOL::FALSE);
    }
    else
    {
      throw new ParserException(make_string_ptr("Invalid 'build' option, should be 'Y' or 'N'. "));
    }
  }

  // return stmt;
  return nullptr;
}

SQLStatement_ptr MySqlStatementParser::parseSubmitJob()
{
  // SQLSubmitJobStatement stmt = new SQLSubmitJobStatement();
  if (lexer->identifierEquals(make_string_ptr("AWAIT")))
  {
    lexer->nextToken();
    // stmt->setAwait(BOOL::TRUE);
  }

  // stmt->setStatment(this->parseStatement());

  // return stmt;
  return nullptr;
}

SQLStatement_ptr MySqlStatementParser::parseSync()
{
  lexer->nextToken();

  if (lexer->identifierEquals(make_string_ptr("RAFT_LEADER_TRANSFER")))
  {
    return parseRaftLeaderTransfer();
  }
  else if (lexer->identifierEquals(make_string_ptr("RAFT_MEMBER_CHANGE")))
  {
    return parseRaftMemeberChange();
  }
  else
  {
    acceptIdentifier("META");
    acceptIdentifier("TABLES");

    // SQLSyncMetaStatement stmt = new SQLSyncMetaStatement();

    if (lexer->token()->name->c_str() == Token::FROM.name->c_str())
    {
      lexer->nextToken();
      // stmt->setFrom(this->exprParser->name());
    }

    if (lexer->token()->name->c_str() == Token::LIKE.name->c_str())
    {
      lexer->nextToken();
      // stmt->setLike(this->exprParser->getExpr());
    }
    // return stmt;
    return nullptr;
  }
}

SQLStatement_ptr MySqlStatementParser::parseFlush()
{
  acceptIdentifier("FLUSH");
  // MySqlFlushStatement stmt = new MySqlFlushStatement();

  if (lexer->identifierEquals(make_string_ptr("NO_WRITE_TO_BINLOG")))
  {
    lexer->nextToken();
    // stmt->setNoWriteToBinlog(BOOL::TRUE);
  }

  if (lexer->identifierEquals(make_string_ptr("LOCAL")))
  {
    lexer->nextToken();
    // stmt->setLocal(BOOL::TRUE);
  }

  for (;;)
  {
    if (lexer->token()->name->c_str() == Token::BINARY.name->c_str() ||
        lexer->identifierEquals(make_string_ptr("BINARY")))
    {
      lexer->nextToken();
      acceptIdentifier("LOGS");
      // stmt->setBinaryLogs(BOOL::TRUE);
    }
    else if (lexer->identifierEquals(make_string_ptr("DES_KEY_FILE")))
    {
      lexer->nextToken();
      // stmt->setDesKeyFile(BOOL::TRUE);
    }
    else if (lexer->identifierEquals(make_string_ptr("ENGINE")))
    {
      lexer->nextToken();
      acceptIdentifier("LOGS");
      // stmt->setEngineLogs(BOOL::TRUE);
    }
    else if (lexer->identifierEquals(make_string_ptr("ERROR")))
    {
      lexer->nextToken();
      acceptIdentifier("LOGS");
      // stmt->setErrorLogs(BOOL::TRUE);
    }
    else if (lexer->identifierEquals(make_string_ptr("GENERAL")))
    {
      lexer->nextToken();
      acceptIdentifier("LOGS");
      // stmt->setGeneralLogs(BOOL::TRUE);
    }
    else if (lexer->identifierEquals(make_string_ptr("HOSTS")))
    {
      lexer->nextToken();
      // stmt->setHots(BOOL::TRUE);
    }
    else if (lexer->identifierEquals(make_string_ptr("LOGS")))
    {
      lexer->nextToken();
      // stmt->setLogs(BOOL::TRUE);
    }
    else if (lexer->identifierEquals(make_string_ptr("PRIVILEGES")))
    {
      lexer->nextToken();
      // stmt->setPrivileges(BOOL::TRUE);
    }
    else if (lexer->identifierEquals(make_string_ptr("OPTIMIZER_COSTS")))
    {
      lexer->nextToken();
      // stmt->setOptimizerCosts(BOOL::TRUE);
    }
    else if (lexer->identifierEquals(make_string_ptr("QUERY")))
    {
      lexer->nextToken();
      accept(Token::CACHE);
      // stmt->setQueryCache(BOOL::TRUE);
    }
    else if (lexer->identifierEquals(make_string_ptr("RELAY")))
    {
      lexer->nextToken();
      acceptIdentifier("LOGS");
      // stmt->setRelayLogs(BOOL::TRUE);
      if (lexer->token()->name->c_str() == Token::FOR.name->c_str())
      {
        lexer->nextToken();
        acceptIdentifier("CHANNEL");
        // stmt->setRelayLogsForChannel(this->exprParser->primary());
      }
    }
    else if (lexer->identifierEquals(make_string_ptr("SLOW")))
    {
      lexer->nextToken();
      acceptIdentifier("LOGS");
      // stmt->setSlowLogs(BOOL::TRUE);
    }
    else if (lexer->identifierEquals(STATUS))
    {
      lexer->nextToken();
      // stmt->setStatus(BOOL::TRUE);
    }
    else if (lexer->identifierEquals(make_string_ptr("USER_RESOURCES")))
    {
      lexer->nextToken();
      // stmt->setUserResources(BOOL::TRUE);
    }
    else if (lexer->token()->name->c_str() == Token::COMMA.name->c_str())
    {
      lexer->nextToken();
      continue;
    }
    else
    {
      break;
    }
  }

  if (lexer->identifierEquals(make_string_ptr("TABLES")) || lexer->token()->name->c_str() == Token::TABLE.name->c_str())
  {
    lexer->nextToken();

    // stmt->setTableOption(BOOL::TRUE);

    if (lexer->token()->name->c_str() == Token::WITH.name->c_str())
    {
      lexer->nextToken();
      acceptIdentifier("READ");
      accept(Token::LOCK);
      // stmt->setWithReadLock(BOOL::TRUE);
    }
    for (;;)
    {
      if (lexer->token()->name->c_str() == Token::IDENTIFIER.name->c_str())
      {
        for (;;)
        {
          SQLName_ptr name = this->exprParser->name();
          // stmt->addTable(name);

          if (lexer->token()->name->c_str() == Token::COMMA.name->c_str())
          {
            lexer->nextToken();
            continue;
          }
          break;
        }
        break;
      }
      break;
    }

    // if (!stmt->getTables().isEmpty()) {
    //     if (lexer->token()->name->c_str() == Token::FOR.name->c_str()) {
    //         lexer->nextToken();
    //         acceptIdentifier("EXPORT");
    //         stmt->setForExport(BOOL::TRUE);
    //     } else if (lexer->token()->name->c_str() == Token::WITH.name->c_str()) {
    //         lexer->nextToken();
    //         acceptIdentifier("READ");
    //         accept(Token::LOCK);
    //         stmt->setWithReadLock(BOOL::TRUE);
    //     } else if (lexer->identifierEquals(FnvHash::Constants::VERSION)) {
    //         lexer->nextToken();
    //         accept(Token::EQ);
    //         stmt->setVersion(this->exprParser->integerExpr());
    //     }
    // }
  }

  // return stmt;
  return nullptr;
}

// SQLBeginStatement* MySqlStatementParser::parseTiDBBeginStatment() {
//     SQLBeginStatement* tidbBegin = new SQLBeginStatement();
//     tidbBegin.setDbType(dbType);
//     accept(Token::BEGIN);
//     if (lexer->token()->name->c_str() == Token::IDENTIFIER.name->c_str()) {
//         tidbBegin.setTidbTxnMode(this->exprParser->name());
//     }
//     return tidbBegin;
// }

SQLStatement_ptr MySqlStatementParser::parseBlock()
{
  SQLBlockStatement_ptr block = SQLBlockStatement_ptr(new SQLBlockStatement());
  block->setDbType(dbType);

  accept(Token::BEGIN);
  SQLStatement_list_ptr statementList = block->getStatementList();
  this->parseStatementList(statementList, -1, block);

  if (lexer->token()->name->c_str() != Token::END.name->c_str() && statementList->size() > 0)
  {
    auto it_statementList = statementList->begin();
    std::advance(it_statementList, statementList->size() - 1);
    if (instanceof <SQLStatement, SQLCommitStatement>(*it_statementList) ||
        instanceof <SQLStatement, SQLRollbackStatement>(*it_statementList))
    {
      block->setEndOfCommit(BOOL::TRUE);
      return block;
    }
  }
  accept(Token::END);

  return block;
}

// MySqlExplainStatement* MySqlStatementParser::parseDescribe() {
//     // see https://dev.mysql.com/doc/refman/5.7/en/explain.html
//     MySqlExplainStatement describe = new MySqlExplainStatement();

//     // {DESCRIBE | DESC}
//     if (lexer->token()->name->c_str() == Token::DESC || lexer->identifierEquals(DESCRIBE)) {
//         lexer->nextToken();
//         describe.setDescribe(BOOL::TRUE);
//     } else {
//         throw new ParserException("expect one of {DESCRIBE | DESC} , actual " + lexer->token() + ", " + lexer->info());
//     }

//     return parseExplain(describe);
// }

// MySqlExplainStatement* MySqlStatementParser::parseExplain() {
//     // see https://dev.mysql.com/doc/refman/5.7/en/explain.html
//     MySqlExplainStatement explain = new MySqlExplainStatement();
//     explain.setSourceLine(lexer->getPosLine());
//     explain.setSourceLine(lexer->getPosColumn());

//     // {EXPLAIN}
//     if (lexer->token()->name->c_str() == Token::EXPLAIN) {
//         lexer->nextToken();
//     } else {
//         throw new ParserException("expect EXPLAIN , actual " + lexer->token() + ", " + lexer->info());
//     }

//     return parseExplain(explain);
// }

// MySqlExplainStatement* MySqlStatementParser::parseExplain(MySqlExplainStatement* explain) {
//     if (lexer->identifierEquals(FnvHash::Constants::PLAN)) {
//         Lexer::SavePoint mark = lexer->mark();
//         lexer->nextToken();
//         if (lexer->token()->name->c_str() == Token::FOR.name->c_str()) {
//             lexer->nextToken();
//         } else {
//             lexer->reset(mark);
//         }
//     }

//     if (lexer->token()->name->c_str() == Token::ANALYZE) {
//         lexer->nextToken();
//         explain.setType("ANALYZE");
//     }

//     if (lexer->token()->name->c_str() == Token::HINT.name->c_str()) {
//         std::list<SQLCommentHint*> hints = this->exprParser->parseHints();
//         explain.setHints(hints);
//     }
//     // see https://dev.mysql.com/doc/refman/5.7/en/explain.html

//     switch (dbType) {
//         case mysql:
//         case ads:
//         case presto:
//         case trino:
//             Lexer::SavePoint mark = lexer->mark();

//             if (lexer->token()->name->c_str() == Token::LPAREN.name->c_str()) {
//                 lexer->nextToken();
//                 if (lexer->token()->name->c_str() == Token::SELECT.name->c_str()) {
//                     lexer->reset(mark);
//                     break;
//                 }

//                 for (; ; ) {
//                     if (lexer->identifierEquals("FORMAT")) {
//                         lexer->nextToken();
//                         string_ptr  format = lexer->stringVal();
//                         explain.setFormat(format);
//                         lexer->nextToken();
//                     } else if (lexer->identifierEquals("TYPE")) {
//                         lexer->nextToken();
//                         string_ptr  type = lexer->stringVal();
//                         explain.setType(type);
//                         lexer->nextToken();
//                     } else {
//                         break;
//                     }

//                     if (lexer->token()->name->c_str() == Token::COMMA.name->c_str()) {
//                         lexer->nextToken();
//                         continue;
//                     } else {
//                         break;
//                     }
//                 }
//                 accept(Token::RPAREN);
//                 explain.setParenthesis(BOOL::TRUE);
//             }
//             break;
//         default:
//             break;
//     }

//     BOOL_ptr table = BOOL::FALSE;
//     if (lexer->token()->name->c_str() == Token::IDENTIFIER.name->c_str()) {
//         long hash = lexer->hashLCase();
//         string_ptr  stringVal = lexer->stringVal();

//         if (hash == FnvHash::Constants::EXTENDED) {
//             explain.setExtended(BOOL::TRUE);
//             lexer->nextToken();
//         } else if (hash == FnvHash::Constants::PARTITIONS) {
//             explain.setType(stringVal);
//             lexer->nextToken();
//         } else if (hash == FnvHash::Constants::OPTIMIZER) {
//             explain.setOptimizer(BOOL::TRUE);
//             lexer->nextToken();
//         } else if (hash == FnvHash::Constants::FORMAT) {
//             lexer->nextToken();
//             accept(Token::EQ);

//             string_ptr  format = lexer->stringVal();
//             explain.setFormat(format);
//             accept(Token::IDENTIFIER);
//         } else {
//             explain.setTableName(exprParser->name());
//             if (lexer->token()->name->c_str() == Token::IDENTIFIER.name->c_str()) {
//                 explain.setColumnName(exprParser->name());
//             } else if (lexer->token()->name->c_str() == Token::LITERAL_CHARS) {
//                 explain.setWild(exprParser->getExpr());
//             }
//             table = BOOL::TRUE;
//         }
//     }

//     if (lexer->token()->name->c_str() == Token::DISTRIBUTE) {
//         lexer->nextToken();
//         acceptIdentifier("INFO");
//         explain.setDistributeInfo(BOOL::TRUE);
//     }

//     if (lexer->token()->name->c_str() == Token::FOR.name->c_str()) {
//         lexer->nextToken();
//         acceptIdentifier(CONNECTION);
//         explain.setConnectionId(exprParser->getExpr());
//     } else if (!table) {
//         explain.setStatement(this->parseStatement());
//     }

//     return explain;
// }

SQLStatement_ptr MySqlStatementParser::parseShow()
{
  accept(Token::SHOW);

  if (lexer->token()->name->c_str() == Token::COMMENT.name->c_str())
  {
    lexer->nextToken();
  }

  BOOL_ptr isPhysical = BOOL::FALSE;

  if (lexer->identifierEquals(FnvHash::Constants::PHYSICAL))
  {
    lexer->nextToken();
    isPhysical = BOOL::TRUE;
  }

  BOOL_ptr full = BOOL::FALSE;
  if (lexer->token()->name->c_str() == Token::FULL.name->c_str())
  {
    lexer->nextToken();
    full = BOOL::TRUE;
  }
  else if (lexer->token()->name->c_str() == Token::HINT.name->c_str())
  {
    string_ptr hints = make_string_ptr(encode_util::UnicodeToUTF8(*lexer->stringVal()));
    hints = StringUtils::toLower(hints);
    if (StringUtils::endWith(hints, make_string_ptr(" full")) &&
        hints->length() <= 11 &&
        hints->at(0) == '!' &&
        hints->at(1) == '5')
    {
      lexer->nextToken();
      full = BOOL::TRUE;
    }
  }

  if (lexer->identifierEquals(FnvHash::Constants::STATS))
  {
    lexer->nextToken();
    // SQLShowStatisticStmt showStats = new SQLShowStatisticStmt();
    // showStats.setDbType(DbType::mysql);
    if (full)
    {
      // showStats.setFull(BOOL::TRUE);
    }
    // return showStats;
  }

  if (lexer->identifierEquals(FnvHash::Constants::PROCESSLIST))
  {
    lexer->nextToken();
    // MySqlShowProcessstd::listStatement stmt = new MySqlShowProcessstd::listStatement();
    // stmt->setFull(full);

    if (!full)
    {
      if (lexer->identifierEquals(FnvHash::Constants::MPP))
      {
        lexer->nextToken();
        // stmt->setMpp(BOOL::TRUE);
      }
    }

    if (lexer->token()->name->c_str() == Token::WHERE.name->c_str())
    {
      lexer->nextToken();
      // stmt->setWhere(this->exprParser->getExpr());
    }

    if (lexer->token()->name->c_str() == Token::ORDER.name->c_str())
    {
      // stmt->setOrderBy(this->exprParser->parseOrderBy());
    }

    if (lexer->token()->name->c_str() == Token::LIMIT.name->c_str())
    {
      // stmt->setLimit(this->exprParser->parseLimit());
    }

    // return stmt;
  }

  if (lexer->identifierEquals(make_string_ptr("COLUMNS")) || lexer->identifierEquals(make_string_ptr("FIELDS")))
  {
    lexer->nextToken();

    // SQLShowColumnsStatement stmt = parseShowColumns();
    // stmt->setFull(full);

    // return stmt;
  }

  if (lexer->identifierEquals(make_string_ptr("COLUMNS")))
  {
    lexer->nextToken();

    // SQLShowColumnsStatement stmt = parseShowColumns();

    // return stmt;
  }

  if (lexer->identifierEquals(TABLES))
  {
    lexer->nextToken();

    // SQLShowTablesStatement stmt = parseShowTables();
    // stmt->setFull(full);

    // return stmt;
  }

  if (lexer->identifierEquals(make_string_ptr("DATABASES")))
  {
    lexer->nextToken();

    // SQLShowDatabasesStatement stmt = parseShowDatabases(isPhysical);

    if (full)
    {
      // stmt->setFull(BOOL::TRUE);
    }

    // return stmt;
  }

  if (lexer->identifierEquals(make_string_ptr("WARNINGS")))
  {
    lexer->nextToken();

    // MySqlShowWarningsStatement stmt = parseShowWarnings();

    // return stmt;
  }

  if (lexer->identifierEquals(make_string_ptr("COUNT")))
  {
    lexer->nextToken();
    accept(Token::LPAREN);
    accept(Token::STAR);
    accept(Token::RPAREN);

    if (lexer->identifierEquals(FnvHash::Constants::ERRORS))
    {
      lexer->nextToken();

      // MySqlShowErrorsStatement stmt = new MySqlShowErrorsStatement();
      // stmt->setCount(BOOL::TRUE);

      // return stmt;
    }
    else
    {
      acceptIdentifier("WARNINGS");

      // MySqlShowWarningsStatement stmt = new MySqlShowWarningsStatement();
      // stmt->setCount(BOOL::TRUE);

      // return stmt;
    }
  }

  if (lexer->identifierEquals(FnvHash::Constants::ERRORS))
  {
    lexer->nextToken();

    // MySqlShowErrorsStatement stmt = new MySqlShowErrorsStatement();
    // stmt->setLimit(this->exprParser->parseLimit());

    // return stmt;
  }

  if (lexer->identifierEquals(STATUS))
  {
    lexer->nextToken();

    // MySqlShowStatusStatement stmt = parseShowStatus();

    // return stmt;
  }

  if (lexer->identifierEquals(DBLOCK))
  {
    lexer->nextToken();

    // return new MysqlShowDbLockStatement();
  }

  if (lexer->identifierEquals(VARIABLES))
  {
    lexer->nextToken();

    // SQLShowVariantsStatement stmt = parseShowVariants();

    // return stmt;
  }

  if (lexer->identifierEquals(GLOBAL))
  {
    lexer->nextToken();

    if (lexer->identifierEquals(STATUS))
    {
      lexer->nextToken();
      // MySqlShowStatusStatement stmt = parseShowStatus();
      // stmt->setGlobal(BOOL::TRUE);
      // return stmt;
    }

    if (lexer->identifierEquals(VARIABLES))
    {
      lexer->nextToken();
      // SQLShowVariantsStatement stmt = parseShowVariants();
      // stmt->setGlobal(BOOL::TRUE);
      // return stmt;
    }

    // DRDS GSI syntax.
    if (isEnabled(SQLParserFeature_ptr(new SQLParserFeature(&SQLParserFeature::DRDSAsyncDDL))) && (Token::INDEX == *lexer->token() || lexer->identifierEquals(make_string_ptr("INDEXES"))))
    {
      lexer->nextToken();

      // DrdsShowGlobalIndex stmt = new DrdsShowGlobalIndex();
      if (Token::FROM == *lexer->token())
      {
        lexer->nextToken();
        // stmt->setTableName(this->exprParser->name());
      }
      // return stmt;
    }
  }

  if (lexer->identifierEquals(FnvHash::Constants::SESSION))
  {
    lexer->nextToken();

    if (lexer->identifierEquals(STATUS))
    {
      lexer->nextToken();
      // MySqlShowStatusStatement stmt = parseShowStatus();
      // stmt->setSession(BOOL::TRUE);
      // return stmt;
    }

    if (lexer->identifierEquals(VARIABLES))
    {
      lexer->nextToken();
      // SQLShowVariantsStatement stmt = parseShowVariants();
      // stmt->setSession(BOOL::TRUE);
      // return stmt;
    }

    // SQLShowSessionStatement stmt = new SQLShowSessionStatement();
    if (lexer->token()->name->c_str() == Token::LIKE.name->c_str())
    {
      lexer->nextToken();
      SQLExpr_ptr like = this->exprParser->getExpr();
      // stmt->setLike(like);
    }
    // return stmt;
  }

  if (lexer->identifierEquals(make_string_ptr("COBAR_STATUS")))
  {
    lexer->nextToken();
    // return new CobarShowStatus();
  }

  if (lexer->identifierEquals(make_string_ptr("AUTHORS")))
  {
    lexer->nextToken();
    // return new MySqlShowAuthorsStatement();
  }

  if (lexer->token()->name->c_str() == Token::BINARY.name->c_str())
  {
    lexer->nextToken();
    acceptIdentifier("LOGS");
    // return new MySqlShowBinaryLogsStatement();
  }

  if (lexer->identifierEquals(make_string_ptr("MASTER")))
  {
    lexer->nextToken();
    if (lexer->identifierEquals(make_string_ptr("LOGS")))
    {
      lexer->nextToken();
      // return new MySqlShowMasterLogsStatement();
    }
    acceptIdentifier(STATUS);
    // return new MySqlShowMasterStatusStatement();
  }

  if (lexer->identifierEquals(make_string_ptr("CLUSTER")))
  {
    lexer->nextToken();
    acceptIdentifier("NAME");
    // return new MySqlShowClusterNameStatement();
  }

  if (lexer->identifierEquals(make_string_ptr("SYNC_JOB")))
  {
    lexer->nextToken();
    acceptIdentifier(STATUS);
    // MySqlShowJobStatusStatement stmt = new MySqlShowJobStatusStatement();
    // stmt->setSync(BOOL::TRUE);
    if (lexer->token()->name->c_str() == Token::WHERE.name->c_str())
    {
      lexer->nextToken();
      // stmt->setWhere(this->exprParser->getExpr());
    }
    // return stmt;
  }
  if (lexer->identifierEquals(make_string_ptr("JOB")))
  {
    lexer->nextToken();
    acceptIdentifier(STATUS);

    // MySqlShowJobStatusStatement stmt = new MySqlShowJobStatusStatement();
    if (lexer->token()->name->c_str() == Token::WHERE.name->c_str())
    {
      lexer->nextToken();
      // stmt->setWhere(this->exprParser->getExpr());
    }
    // return stmt;
  }
  if (lexer->identifierEquals(make_string_ptr("MIGRATE")))
  {
    lexer->nextToken();

    acceptIdentifier("TASK");
    acceptIdentifier(STATUS);

    // MySqlShowMigrateTaskStatusStatement stmt = new MySqlShowMigrateTaskStatusStatement();
    if (lexer->token()->name->c_str() == Token::WHERE.name->c_str())
    {
      lexer->nextToken();
      // stmt->setWhere(this->exprParser->getExpr());
    }
    // return stmt;
  }

  if (lexer->identifierEquals(FnvHash::Constants::CHARSET))
  {
    lexer->nextToken();

    // MySqlShowCharacterSetStatement stmt = new MySqlShowCharacterSetStatement();

    if (lexer->token()->name->c_str() == Token::LIKE.name->c_str())
    {
      lexer->nextTokenValue();
      // stmt->setPattern(this->exprParser->getExpr());
    }

    if (lexer->token()->name->c_str() == Token::WHERE.name->c_str())
    {
      lexer->nextToken();
      // stmt->setWhere(this->exprParser->getExpr());
    }

    // return stmt;
  }

  if (lexer->identifierEquals(FnvHash::Constants::CHARACTER))
  {
    lexer->nextToken();
    accept(Token::SET);
    // MySqlShowCharacterSetStatement stmt = new MySqlShowCharacterSetStatement();

    if (lexer->token()->name->c_str() == Token::LIKE.name->c_str())
    {
      lexer->nextTokenValue();
      // stmt->setPattern(this->exprParser->getExpr());
    }

    if (lexer->token()->name->c_str() == Token::WHERE.name->c_str())
    {
      lexer->nextToken();
      // stmt->setWhere(this->exprParser->getExpr());
    }

    // return stmt;
  }

  if (lexer->identifierEquals(make_string_ptr("COLLATION")))
  {
    lexer->nextToken();
    // MySqlShowCollationStatement stmt = new MySqlShowCollationStatement();

    if (lexer->token()->name->c_str() == Token::LIKE.name->c_str())
    {
      lexer->nextTokenValue();
      // stmt->setPattern(this->exprParser->getExpr());
    }

    if (lexer->token()->name->c_str() == Token::WHERE.name->c_str())
    {
      lexer->nextToken();
      // stmt->setWhere(this->exprParser->getExpr());
    }

    // return stmt;
  }

  if (lexer->identifierEquals(BINLOG))
  {
    lexer->nextToken();
    acceptIdentifier(EVENTS);
    // MySqlShowBinLogEventsStatement stmt = new MySqlShowBinLogEventsStatement();

    if (lexer->token()->name->c_str() == Token::IN.name->c_str())
    {
      lexer->nextToken();
      // stmt->setIn(this->exprParser->getExpr());
    }

    if (lexer->token()->name->c_str() == Token::FROM.name->c_str())
    {
      lexer->nextToken();
      // stmt->setFrom(this->exprParser->getExpr());
    }

    // stmt->setLimit(this->exprParser->parseLimit());

    // return stmt;
  }

  if (lexer->identifierEquals(make_string_ptr("CONTRIBUTORS")))
  {
    lexer->nextToken();
    // return new MySqlShowContributorsStatement();
  }

  if (lexer->token()->name->c_str() == Token::ALL.name->c_str())
  {
    lexer->nextToken();
    accept(Token::CREATE);
    accept(Token::TABLE);

    // SQLShowCreateTableStatement stmt = new SQLShowCreateTableStatement();
    // stmt->setAll(BOOL::TRUE);
    // stmt->setName(this->exprParser->name());
    // return stmt;
  }

  if (lexer->token()->name->c_str() == Token::CREATE.name->c_str())
  {
    lexer->nextToken();

    if (lexer->token()->name->c_str() == Token::DATABASE.name->c_str() || lexer->token()->name->c_str() == Token::SCHEMA.name->c_str())
    {
      lexer->nextToken();

      // MySqlShowCreateDatabaseStatement stmt = new MySqlShowCreateDatabaseStatement();
      if (lexer->token()->name->c_str() == Token::IF.name->c_str())
      {
        lexer->nextToken();
        accept(Token::NOT);
        accept(Token::EXISTS);
        // stmt->setIfNotExists(BOOL::TRUE);
      }
      // stmt->setDatabase(this->exprParser->name());
      // return stmt;
    }

    if (lexer->identifierEquals(make_string_ptr("EVENT")))
    {
      lexer->nextToken();

      // MySqlShowCreateEventStatement stmt = new MySqlShowCreateEventStatement();
      // stmt->setEventName(this->exprParser->name());
      // return stmt;
    }

    if (lexer->token()->name->c_str() == Token::FUNCTION.name->c_str())
    {
      lexer->nextToken();

      // MySqlShowCreateFunctionStatement stmt = new MySqlShowCreateFunctionStatement();
      // stmt->setName(this->exprParser->name());
      // return stmt;
    }

    if (lexer->token()->name->c_str() == Token::PROCEDURE.name->c_str())
    {
      lexer->nextToken();

      // MySqlShowCreateProcedureStatement stmt = new MySqlShowCreateProcedureStatement();
      // stmt->setName(this->exprParser->name());
      // return stmt;
    }
    if (lexer->token()->name->c_str() == Token::TABLE.name->c_str())
    {
      lexer->nextToken();
      // SQLShowCreateTableStatement stmt = new SQLShowCreateTableStatement();

      if (lexer->token()->name->c_str() != Token::LIKE.name->c_str())
      {
        // stmt->setName(this->exprParser->name());
      }

      if (lexer->token()->name->c_str() == Token::LIKE.name->c_str())
      {
        lexer->nextToken();
        if (lexer->identifierEquals(FnvHash::Constants::MAPPING))
        {
          lexer->nextToken();
          accept(Token::LPAREN);
          SQLName_ptr name = this->exprParser->name();
          // stmt->setLikeMapping(name);
          accept(Token::RPAREN);
        }
      }

      // return stmt;
    }

    if (lexer->token()->name->c_str() == Token::VIEW.name->c_str())
    {
      lexer->nextToken();

      // SQLShowCreateViewStatement stmt = new SQLShowCreateViewStatement();
      // stmt->setName(this->exprParser->name());
      // return stmt;
    }

    if (lexer->token()->name->c_str() == Token::TRIGGER.name->c_str())
    {
      lexer->nextToken();

      // MySqlShowCreateTriggerStatement stmt = new MySqlShowCreateTriggerStatement();
      // stmt->setName(this->exprParser->name());
      // return stmt;
    }

    if (lexer->token()->name->c_str() == Token::FULLTEXT.name->c_str())
    {
      lexer->nextToken();
      // MysqlShowCreateFullTextStatement stmt = new MysqlShowCreateFullTextStatement();

      // stmt->setType(parseFullTextType());

      // stmt->setName(this->exprParser->name());
      // return stmt;
    }

    if (lexer->identifierEquals(make_string_ptr("MATERIALIZED")))
    {
      lexer->nextToken();
      // SQLShowCreateMaterializedViewStatement stmt = new SQLShowCreateMaterializedViewStatement();
      accept(Token::VIEW);

      // stmt->setName(this->exprParser->name());
      // return stmt;
    }

    throw new ParserException(make_string_ptr("TODO " + encode_util::UnicodeToUTF8(lexer->info())));
  }

  if (lexer->identifierEquals(ENGINE))
  {
    lexer->nextToken();
    // MySqlShowEngineStatement stmt = new MySqlShowEngineStatement();
    // stmt->setName(this->exprParser->name());
    // stmt->setOption(MySqlShowEngineStatement.Option.valueOf(lexer->stringVal().toUpperCase()));
    lexer->nextToken();
    // return stmt;
  }

  if (lexer->token()->name->c_str() == Token::DATABASE.name->c_str() ||
      lexer->identifierEquals(FnvHash::Constants::DB))
  {
    lexer->nextToken();

    // MySqlShowDatabaseStatusStatement* stmt = new MySqlShowDatabaseStatusStatement();

    if (full)
    {
      // stmt->setFull(BOOL::TRUE);
    }

    if (lexer->identifierEquals(make_string_ptr("STATUS")))
    {
      lexer->nextToken();

      if (lexer->token()->name->c_str() == Token::LIKE.name->c_str())
      {
        lexer->nextTokenValue();
        // stmt->setName(this->exprParser->name());
      }
      else
      {
        if (lexer->token()->name->c_str() == Token::WHERE.name->c_str())
        {
          lexer->nextToken();
          SQLExpr_ptr where = exprParser->getExpr();
          // stmt->setWhere(where);
        }

        if (lexer->token()->name->c_str() == Token::ORDER.name->c_str())
        {
          SQLOrderBy_ptr orderBy = exprParser->parseOrderBy();
          // stmt->setOrderBy(orderBy);
        }

        if (lexer->token()->name->c_str() == Token::LIMIT.name->c_str())
        {
          SQLLimit_ptr limit = exprParser->parseLimit();
          // stmt->setLimit(limit);
        }
      }
    }
    // return stmt;
  }

  if (lexer->identifierEquals(make_string_ptr("STORAGE")))
  {
    lexer->nextToken();
    acceptIdentifier(ENGINES);
    // MySqlShowEnginesStatement stmt = new MySqlShowEnginesStatement();
    // stmt->setStorage(BOOL::TRUE);
    // return stmt;
  }

  if (lexer->identifierEquals(ENGINES))
  {
    lexer->nextToken();
    // MySqlShowEnginesStatement stmt = new MySqlShowEnginesStatement();
    // return stmt;
  }

  if (lexer->identifierEquals(EVENTS))
  {
    lexer->nextToken();
    // MySqlShowEventsStatement stmt = new MySqlShowEventsStatement();

    if (lexer->token()->name->c_str() == Token::FROM.name->c_str() || lexer->token()->name->c_str() == Token::IN.name->c_str())
    {
      lexer->nextToken();
      // stmt->setSchema(this->exprParser->name());
    }

    if (lexer->token()->name->c_str() == Token::LIKE.name->c_str())
    {
      lexer->nextTokenValue();
      // stmt->setLike(this->exprParser->getExpr());
    }

    if (lexer->token()->name->c_str() == Token::WHERE.name->c_str())
    {
      lexer->nextToken();
      // stmt->setWhere(this->exprParser->getExpr());
    }
    // return stmt;
  }

  if (lexer->token()->name->c_str() == Token::FUNCTION.name->c_str())
  {
    lexer->nextToken();

    if (lexer->identifierEquals(make_string_ptr("CODE")))
    {
      lexer->nextToken();
      // MySqlShowFunctionCodeStatement stmt = new MySqlShowFunctionCodeStatement();
      // stmt->setName(this->exprParser->name());
      // return stmt;
    }

    acceptIdentifier(STATUS);
    // MySqlShowFunctionStatusStatement stmt = new MySqlShowFunctionStatusStatement();

    if (lexer->token()->name->c_str() == Token::LIKE.name->c_str())
    {
      lexer->nextTokenValue();
      // stmt->setLike(this->exprParser->getExpr());
    }

    if (lexer->token()->name->c_str() == Token::WHERE.name->c_str())
    {
      lexer->nextToken();
      // stmt->setWhere(this->exprParser->getExpr());
    }
    // return stmt;
  }

  // MySqlShowFunctionStatusStatement

  if (lexer->identifierEquals(ENGINE))
  {
    lexer->nextToken();
    // MySqlShowEngineStatement stmt = new MySqlShowEngineStatement();
    // stmt->setName(this->exprParser->name());
    // stmt->setOption(MySqlShowEngineStatement.Option.valueOf(lexer->stringVal().toUpperCase()));
    lexer->nextToken();
    // return stmt;
  }

  if (lexer->identifierEquals(make_string_ptr("STORAGE")))
  {
    lexer->nextToken();
    accept(Token::EQ);
    accept(Token::DEFAULT);
    // MySqlShowEnginesStatement stmt = new MySqlShowEnginesStatement();
    // stmt->setStorage(BOOL::TRUE);
    // return stmt;
  }

  //        if (lexer->identifierEquals(make_string_ptr("KEYS")) || lexer->token()->name->c_str() == Token::INDEX) {
  //            lexer->nextToken();
  //            accept(Token::FROM);
  //            MySqlShowKeysStatement stmt = new MySqlShowKeysStatement();
  //            stmt->setTable(exprParser->name());
  //            return stmt;
  //        }

  if (lexer->identifierEquals(make_string_ptr("GRANTS")))
  {
    lexer->nextToken();
    // MySqlShowGrantsStatement stmt = new MySqlShowGrantsStatement();

    if (lexer->token()->name->c_str() == Token::FOR.name->c_str())
    {
      lexer->nextToken();
      // stmt->setUser(this->exprParser->getExpr());
    }

    if (lexer->token()->name->c_str() == Token::ON.name->c_str())
    {
      lexer->nextToken();
      SQLExpr_ptr on = this->exprParser->getExpr();
      // stmt->setOn(on);
    }

    // return stmt;
  }

  if (lexer->token()->name->c_str() == Token::INDEX.name->c_str() ||
      lexer->identifierEquals(make_string_ptr("INDEXES")) ||
      lexer->identifierEquals(make_string_ptr("KEYS")))
  {
    // SQLShowIndexesStatement stmt = new SQLShowIndexesStatement();

    // stmt->setType(lexer->stringVal());
    lexer->nextToken();

    if (lexer->token()->name->c_str() == Token::FROM.name->c_str() ||
        lexer->token()->name->c_str() == Token::IN.name->c_str())
    {
      lexer->nextToken();
      SQLName_ptr table = exprParser->name();
      // stmt->setTable(table);

      if (lexer->token()->name->c_str() == Token::FROM.name->c_str() ||
          lexer->token()->name->c_str() == Token::IN.name->c_str())
      {
        lexer->nextToken();
        SQLName_ptr database = exprParser->name();
        // stmt->setDatabase(database->toString());
      }

      if (lexer->token()->name->c_str() == Token::WHERE.name->c_str())
      {
        lexer->nextToken();
        SQLExpr_ptr where = exprParser->getExpr();
        // stmt->setWhere(where);
      }
    }

    if (lexer->token()->name->c_str() == Token::HINT.name->c_str())
    {
      // stmt->setHints(this->exprParser->parseHints());
    }

    // return stmt;
  }

  if (lexer->token()->name->c_str() == Token::OPEN.name->c_str() ||
      lexer->identifierEquals(make_string_ptr("OPEN")))
  {
    lexer->nextToken();
    acceptIdentifier(TABLES);
    // MySqlShowOpenTablesStatement stmt = new MySqlShowOpenTablesStatement();

    if (lexer->token()->name->c_str() == Token::FROM.name->c_str() ||
        lexer->token()->name->c_str() == Token::IN.name->c_str())
    {
      lexer->nextToken();
      // stmt->setDatabase(this->exprParser->name());
    }

    if (lexer->token()->name->c_str() == Token::LIKE.name->c_str())
    {
      lexer->nextTokenValue();
      // stmt->setLike(this->exprParser->getExpr());
    }

    if (lexer->token()->name->c_str() == Token::WHERE.name->c_str())
    {
      lexer->nextToken();
      // stmt->setWhere(this->exprParser->getExpr());
    }
    // return stmt;
  }

  if (lexer->identifierEquals(make_string_ptr("PLUGINS")))
  {
    lexer->nextToken();
    // MySqlShowPluginsStatement stmt = new MySqlShowPluginsStatement();
    // return stmt;
  }

  if (lexer->identifierEquals(make_string_ptr("HTC")))
  {
    lexer->nextToken();
    // MysqlShowHtcStatement stmt = new MysqlShowHtcStatement();
    // stmt->setFull(BOOL::FALSE);
    // return stmt;
  }

  if (lexer->identifierEquals(make_string_ptr("HMSMETA")))
  {
    lexer->nextToken();
    SQLName_ptr name = this->exprParser->name();

    // MySqlShowHMSMetaStatement stmt = new MySqlShowHMSMetaStatement();
    // stmt->setName(name);
    // return stmt;
  }

  if (lexer->identifierEquals(make_string_ptr("STC")))
  {
    lexer->nextToken();
    // MysqlShowStcStatement stmt = new MysqlShowStcStatement();
    if (lexer->identifierEquals(make_string_ptr("HIS")))
    {
      lexer->nextToken();
      // stmt->setHis(BOOL::TRUE);
    }
    else
    {
      // stmt->setHis(BOOL::FALSE);
    }
    // return stmt;
  }

  if (lexer->identifierEquals(make_string_ptr("PRIVILEGES")))
  {
    lexer->nextToken();
    // MySqlShowPrivilegesStatement stmt = new MySqlShowPrivilegesStatement();
    // return stmt;
  }

  if (lexer->token()->name->c_str() == Token::PROCEDURE.name->c_str())
  {
    lexer->nextToken();

    if (lexer->identifierEquals(make_string_ptr("CODE")))
    {
      lexer->nextToken();
      // MySqlShowProcedureCodeStatement stmt = new MySqlShowProcedureCodeStatement();
      // stmt->setName(this->exprParser->name());
      // return stmt;
    }

    acceptIdentifier(STATUS);
    // MySqlShowProcedureStatusStatement stmt = new MySqlShowProcedureStatusStatement();

    if (lexer->token()->name->c_str() == Token::LIKE.name->c_str())
    {
      lexer->nextTokenValue();
      // stmt->setLike(this->exprParser->getExpr());
    }

    if (lexer->token()->name->c_str() == Token::WHERE.name->c_str())
    {
      lexer->nextToken();
      // stmt->setWhere(this->exprParser->getExpr());
    }
    // return stmt;
  }

  if (lexer->identifierEquals(make_string_ptr("PROFILES")))
  {
    lexer->nextToken();
    // MySqlShowProfilesStatement stmt = new MySqlShowProfilesStatement();
    // return stmt;
  }

  if (lexer->identifierEquals(make_string_ptr("PROFILE")))
  {
    lexer->nextToken();
    // MySqlShowProfileStatement stmt = new MySqlShowProfileStatement();

    for (;;)
    {
      if (lexer->token()->name->c_str() == Token::ALL.name->c_str())
      {
        // stmt->getTypes().add(MySqlShowProfileStatement.Type.ALL);
        lexer->nextToken();
      }
      else if (lexer->identifierEquals(make_string_ptr("BLOCK")))
      {
        lexer->nextToken();
        acceptIdentifier("IO");
        // stmt->getTypes().add(MySqlShowProfileStatement.Type.BLOCK_IO);
      }
      else if (lexer->identifierEquals(make_string_ptr("CONTEXT")))
      {
        lexer->nextToken();
        acceptIdentifier("SWITCHES");
        // stmt->getTypes().add(MySqlShowProfileStatement.Type.CONTEXT_SWITCHES);
      }
      else if (lexer->identifierEquals(make_string_ptr("CPU")))
      {
        lexer->nextToken();
        // stmt->getTypes().add(MySqlShowProfileStatement.Type.CPU);
      }
      else if (lexer->identifierEquals(make_string_ptr("IPC")))
      {
        lexer->nextToken();
        // stmt->getTypes().add(MySqlShowProfileStatement.Type.IPC);
      }
      else if (lexer->identifierEquals(make_string_ptr("MEMORY")))
      {
        lexer->nextToken();
        // stmt->getTypes().add(MySqlShowProfileStatement.Type.MEMORY);
      }
      else if (lexer->identifierEquals(make_string_ptr("PAGE")))
      {
        lexer->nextToken();
        acceptIdentifier("FAULTS");
        // stmt->getTypes().add(MySqlShowProfileStatement.Type.PAGE_FAULTS);
      }
      else if (lexer->identifierEquals(make_string_ptr("SOURCE")))
      {
        lexer->nextToken();
        // stmt->getTypes().add(MySqlShowProfileStatement.Type.SOURCE);
      }
      else if (lexer->identifierEquals(make_string_ptr("SWAPS")))
      {
        lexer->nextToken();
        // stmt->getTypes().add(MySqlShowProfileStatement.Type.SWAPS);
      }
      else
      {
        break;
      }

      if (lexer->token()->name->c_str() == Token::COMMA.name->c_str())
      {
        lexer->nextToken();
        continue;
      }
      break;
    }

    if (lexer->token()->name->c_str() == Token::FOR.name->c_str())
    {
      lexer->nextToken();
      acceptIdentifier("QUERY");
      // stmt->setForQuery(this->exprParser->primary());
    }

    // stmt->setLimit(this->exprParser->parseLimit());

    // return stmt;
  }

  if (lexer->identifierEquals(make_string_ptr("RELAYLOG")))
  {
    lexer->nextToken();
    acceptIdentifier(EVENTS);
    // MySqlShowRelayLogEventsStatement stmt = new MySqlShowRelayLogEventsStatement();

    if (lexer->token()->name->c_str() == Token::IN.name->c_str())
    {
      lexer->nextToken();
      // stmt->setLogName(this->exprParser->primary());
    }

    if (lexer->token()->name->c_str() == Token::FROM.name->c_str())
    {
      lexer->nextToken();
      // stmt->setFrom(this->exprParser->primary());
    }

    // stmt->setLimit(this->exprParser->parseLimit());

    // return stmt;
  }

  if (lexer->identifierEquals(make_string_ptr("RELAYLOG")))
  {
    lexer->nextToken();
    acceptIdentifier(EVENTS);
    // MySqlShowRelayLogEventsStatement stmt = new MySqlShowRelayLogEventsStatement();

    if (lexer->token()->name->c_str() == Token::IN.name->c_str())
    {
      lexer->nextToken();
      // stmt->setLogName(this->exprParser->primary());
    }

    if (lexer->token()->name->c_str() == Token::FROM.name->c_str())
    {
      lexer->nextToken();
      // stmt->setFrom(this->exprParser->primary());
    }

    // stmt->setLimit(this->exprParser->parseLimit());

    // return stmt;
  }

  if (lexer->identifierEquals(make_string_ptr("SLAVE")))
  {
    lexer->nextToken();
    if (lexer->identifierEquals(STATUS))
    {
      lexer->nextToken();
      // return new MySqlShowSlaveStatusStatement();
    }
    else
    {
      acceptIdentifier("HOSTS");
      // MySqlShowSlaveHostsStatement stmt = new MySqlShowSlaveHostsStatement();
      // return stmt;
    }
  }

  if (lexer->token()->name->c_str() == Token::TABLE.name->c_str())
  {
    lexer->nextToken();
    acceptIdentifier(STATUS);
    // MySqlShowTableStatusStatement stmt = new MySqlShowTableStatusStatement();
    if (lexer->token()->name->c_str() == Token::FROM.name->c_str() ||
        lexer->token()->name->c_str() == Token::IN.name->c_str())
    {
      lexer->nextToken();

      SQLName_ptr name = this->exprParser->name();
      if (instanceof <SQLName, SQLPropertyExpr>(name))
      {
        // stmt->setDatabase((SQLIdentifierExpr) ((SQLPropertyExpr) name).getOwner());
        // stmt->setTableGroup(new SQLIdentifierExpr(((SQLPropertyExpr) name).getName()));
      }
      else
      {
        // stmt->setDatabase(name);
      }
    }

    if (lexer->token()->name->c_str() == Token::LIKE.name->c_str())
    {
      lexer->nextTokenValue();
      // stmt->setLike(this->exprParser->getExpr());
    }

    if (lexer->token()->name->c_str() == Token::WHERE.name->c_str())
    {
      lexer->nextToken();
      // stmt->setWhere(this->exprParser->getExpr());
    }

    // return stmt;
  }

  if (lexer->identifierEquals(make_string_ptr("TRIGGERS")))
  {
    lexer->nextToken();
    // MySqlShowTriggersStatement stmt = new MySqlShowTriggersStatement();

    if (lexer->token()->name->c_str() == Token::FROM.name->c_str() ||
        lexer->token()->name->c_str() == Token::IN.name->c_str())
    {
      lexer->nextToken();
      SQLName_ptr database = exprParser->name();
      // stmt->setDatabase(database);
    }

    if (lexer->token()->name->c_str() == Token::LIKE.name->c_str())
    {
      lexer->nextTokenValue();
      SQLExpr_ptr like = exprParser->getExpr();
      // stmt->setLike(like);
    }

    if (lexer->token()->name->c_str() == Token::WHERE.name->c_str())
    {
      lexer->nextToken();
      SQLExpr_ptr where = exprParser->getExpr();
      // stmt->setWhere(where);
    }

    // return stmt;
  }

  if (lexer->identifierEquals(FnvHash::Constants::BROADCASTS))
  {
    lexer->nextToken();
    // MySqlShowBroadcastsStatement stmt = new MySqlShowBroadcastsStatement();

    if (lexer->token()->name->c_str() == Token::WHERE.name->c_str())
    {
      lexer->nextToken();
      SQLExpr_ptr where = exprParser->getExpr();
      // stmt->setWhere(where);
    }

    if (lexer->token()->name->c_str() == Token::ORDER.name->c_str())
    {
      SQLOrderBy_ptr orderBy = exprParser->parseOrderBy();
      // stmt->setOrderBy(orderBy);
    }

    if (lexer->token()->name->c_str() == Token::LIMIT.name->c_str())
    {
      SQLLimit_ptr limit = exprParser->parseLimit();
      // stmt->setLimit(limit);
    }

    // return stmt;
  }

  if (lexer->identifierEquals(FnvHash::Constants::DATASOURCES))
  {
    lexer->nextToken();
    // MySqlShowDatasourcesStatement* stmt = new MySqlShowDatasourcesStatement();

    if (lexer->token()->name->c_str() == Token::WHERE.name->c_str())
    {
      lexer->nextToken();
      SQLExpr_ptr where = exprParser->getExpr();
      // stmt->setWhere(where);
    }

    if (lexer->token()->name->c_str() == Token::ORDER.name->c_str())
    {
      SQLOrderBy_ptr orderBy = exprParser->parseOrderBy();
      // stmt->setOrderBy(orderBy);
    }

    if (lexer->token()->name->c_str() == Token::LIMIT.name->c_str())
    {
      SQLLimit_ptr limit = exprParser->parseLimit();
      // stmt->setLimit(limit);
    }

    // return stmt;
  }

  if (lexer->identifierEquals(FnvHash::Constants::NODE))
  {
    lexer->nextToken();
    // MySqlShowNodeStatement stmt = new MySqlShowNodeStatement();

    if (lexer->token()->name->c_str() == Token::WHERE.name->c_str())
    {
      lexer->nextToken();
      SQLExpr_ptr where = exprParser->getExpr();
      // stmt->setWhere(where);
    }

    if (lexer->token()->name->c_str() == Token::ORDER.name->c_str())
    {
      SQLOrderBy_ptr orderBy = exprParser->parseOrderBy();
      // stmt->setOrderBy(orderBy);
    }

    if (lexer->token()->name->c_str() == Token::LIMIT.name->c_str())
    {
      SQLLimit_ptr limit = exprParser->parseLimit();
      // stmt->setLimit(limit);
    }

    // return stmt;
  }

  if (lexer->identifierEquals(FnvHash::Constants::HELP))
  {
    lexer->nextToken();
    // MySqlShowHelpStatement stmt = new MySqlShowHelpStatement();

    if (lexer->token()->name->c_str() == Token::WHERE.name->c_str())
    {
      lexer->nextToken();
      SQLExpr_ptr where = exprParser->getExpr();
      // stmt->setWhere(where);
    }

    if (lexer->token()->name->c_str() == Token::ORDER.name->c_str())
    {
      SQLOrderBy_ptr orderBy = exprParser->parseOrderBy();
      // stmt->setOrderBy(orderBy);
    }

    if (lexer->token()->name->c_str() == Token::LIMIT.name->c_str())
    {
      SQLLimit_ptr limit = exprParser->parseLimit();
      // stmt->setLimit(limit);
    }

    // return stmt;
  }

  if (lexer->token()->name->c_str() == Token::SEQUENCE.name->c_str() ||
      lexer->identifierEquals(FnvHash::Constants::SEQUENCES))
  {
    lexer->nextToken();
    // MySqlShowSequencesStatement stmt = new MySqlShowSequencesStatement();

    if (lexer->token()->name->c_str() == Token::WHERE.name->c_str())
    {
      lexer->nextToken();
      SQLExpr_ptr where = exprParser->getExpr();
      // stmt->setWhere(where);
    }

    if (lexer->token()->name->c_str() == Token::ORDER.name->c_str())
    {
      SQLOrderBy_ptr orderBy = exprParser->parseOrderBy();
      // stmt->setOrderBy(orderBy);
    }

    if (lexer->token()->name->c_str() == Token::LIMIT.name->c_str())
    {
      SQLLimit_ptr limit = exprParser->parseLimit();
      // stmt->setLimit(limit);
    }

    // return stmt;
  }

  if (lexer->identifierEquals(make_string_ptr("PARTITIONS")))
  {
    lexer->nextToken();
    // SQLShowPartitionsStmt stmt = new SQLShowPartitionsStmt();

    if (lexer->token()->name->c_str() == Token::FROM.name->c_str())
    {
      lexer->nextToken();
    }

    SQLName_ptr name = exprParser->name();
    // stmt->setTableSource(name);

    if (lexer->token()->name->c_str() == Token::PARTITION.name->c_str())
    {
      lexer->nextToken();
      accept(Token::LPAREN);
      // parseAssignItems(stmt->getPartition(), stmt, BOOL::FALSE);
      accept(Token::RPAREN);
    }

    if (lexer->token()->name->c_str() == Token::WHERE.name->c_str())
    {
      lexer->nextToken();
      // stmt->setWhere(this->exprParser->getExpr());
    }

    // return stmt;
  }

  if (lexer->identifierEquals(make_string_ptr("RULE")))
  {
    lexer->nextToken();

    BOOL_ptr version = BOOL::FALSE;
    if (lexer->identifierEquals(FnvHash::Constants::VERSION))
    {
      version = BOOL::TRUE;
      lexer->nextToken();
    }
    else if (lexer->identifierEquals(FnvHash::Constants::FULL) ||
             lexer->token()->name->c_str() == Token::FULL.name->c_str())
    {
      full = BOOL::TRUE;
      lexer->nextToken();
    }

    if (lexer->identifierEquals(FnvHash::Constants::STATUS))
    {
      lexer->nextToken();
      // MySqlShowRuleStatusStatement stmt = new MySqlShowRuleStatusStatement();

      if (full)
      {
        // stmt->setFull(full);
      }

      if (version)
      {
        // stmt->setVersion(BOOL::TRUE);
      }

      if (lexer->token()->name->c_str() == Token::FROM.name->c_str())
      {
        lexer->nextToken();
      }

      if (full)
      {
        // stmt->setLite(BOOL::FALSE);
      }

      if (lexer->token()->name->c_str() == Token::WHERE.name->c_str())
      {
        lexer->nextToken();
        SQLExpr_ptr where = exprParser->getExpr();
        // stmt->setWhere(where);
      }

      if (lexer->token()->name->c_str() == Token::ORDER.name->c_str())
      {
        SQLOrderBy_ptr orderBy = exprParser->parseOrderBy();
        // stmt->setOrderBy(orderBy);
      }

      if (lexer->token()->name->c_str() == Token::LIMIT.name->c_str())
      {
        SQLLimit_ptr limit = exprParser->parseLimit();
        // stmt->setLimit(limit);
      }

      // return stmt;
    }
    else
    {
      // MySqlShowRuleStatement stmt = new MySqlShowRuleStatement();

      if (full)
      {
        // stmt->setFull(full);
      }

      if (version)
      {
        // stmt->setVersion(BOOL::TRUE);
      }

      if (lexer->identifierEquals(FnvHash::Constants::VERSION))
      {
        lexer->nextToken();
        // stmt->setVersion(BOOL::TRUE);
      }

      if (lexer->token()->name->c_str() == Token::XEOF.name->c_str() ||
          lexer->token()->name->c_str() == Token::SEMI.name->c_str())
      {
        // return stmt;
      }

      if (lexer->token()->name->c_str() == Token::FROM.name->c_str())
      {
        lexer->nextToken();

        // stmt->setName(exprParser->name());
      }

      if (lexer->token()->name->c_str() == Token::WHERE.name->c_str())
      {
        lexer->nextToken();
        SQLExpr_ptr where = exprParser->getExpr();
        // stmt->setWhere(where);
      }

      if (lexer->token()->name->c_str() == Token::ORDER.name->c_str())
      {
        SQLOrderBy_ptr orderBy = exprParser->parseOrderBy();
        // stmt->setOrderBy(orderBy);
      }

      if (lexer->token()->name->c_str() == Token::LIMIT.name->c_str())
      {
        SQLLimit_ptr limit = exprParser->parseLimit();
        // stmt->setLimit(limit);
      }
      // return stmt;
    }
  }

  if (lexer->identifierEquals(make_string_ptr("DS")))
  {
    lexer->nextToken();
    // MySqlShowDsStatement* stmt = new MySqlShowDsStatement();

    if (lexer->token()->name->c_str() == Token::WHERE.name->c_str())
    {
      lexer->nextToken();
      SQLExpr_ptr where = exprParser->getExpr();
      // stmt->setWhere(where);
    }

    if (lexer->token()->name->c_str() == Token::ORDER.name->c_str())
    {
      SQLOrderBy_ptr orderBy = exprParser->parseOrderBy();
      // stmt->setOrderBy(orderBy);
    }

    if (lexer->token()->name->c_str() == Token::LIMIT.name->c_str())
    {
      SQLLimit_ptr limit = exprParser->parseLimit();
      // stmt->setLimit(limit);
    }

    // return stmt;
  }

  if (lexer->identifierEquals(make_string_ptr("DDL")))
  {
    lexer->nextToken();

    // DRDS async DDL.
    if (isEnabled(SQLParserFeature_ptr(new SQLParserFeature(&SQLParserFeature::DRDSAsyncDDL))) && !lexer->identifierEquals(make_string_ptr("STATUS")))
    {
      // SHOW [FULL] DDL.
      // DrdsShowDDLJobs showDDLJobs = new DrdsShowDDLJobs();
      // showDDLJobs.setFull(full);

      while (lexer->token()->name->c_str() != Token::XEOF.name->c_str() && lexer->token()->name->c_str() != Token::SEMI.name->c_str())
      {
        // showDDLJobs.addJobId(lexer->integerValue().longValue());
        accept(Token::LITERAL_INT);
        if (Token::COMMA == *lexer->token())
        {
          lexer->nextToken();
        }
        else if (lexer->token()->name->c_str() == Token::XEOF.name->c_str() || lexer->token()->name->c_str() == Token::SEMI.name->c_str())
        {
          break;
        }
        else
        {
          throw new ParserException(make_string_ptr("syntax error, expect job id, actual " + *lexer->token()->getName() + ", " + encode_util::UnicodeToUTF8(lexer->info())));
        }
      }
      // return showDDLJobs;
    }

    acceptIdentifier("STATUS");
    // MySqlShowDdlStatusStatement* stmt = new MySqlShowDdlStatusStatement();

    if (lexer->token()->name->c_str() == Token::WHERE.name->c_str())
    {
      lexer->nextToken();
      SQLExpr_ptr where = exprParser->getExpr();
      // stmt->setWhere(where);
    }

    if (lexer->token()->name->c_str() == Token::ORDER.name->c_str())
    {
      SQLOrderBy_ptr orderBy = exprParser->parseOrderBy();
      // stmt->setOrderBy(orderBy);
    }

    if (lexer->token()->name->c_str() == Token::LIMIT.name->c_str())
    {
      SQLLimit_ptr limit = exprParser->parseLimit();
      // stmt->setLimit(limit);
    }

    // return stmt;
  }

  if (lexer->identifierEquals(make_string_ptr("TRACE")))
  {
    lexer->nextToken();
    // MySqlShowTraceStatement* stmt = new MySqlShowTraceStatement();

    if (lexer->token()->name->c_str() == Token::WHERE.name->c_str())
    {
      lexer->nextToken();
      SQLExpr_ptr where = exprParser->getExpr();
      // stmt->setWhere(where);
    }

    if (lexer->token()->name->c_str() == Token::ORDER.name->c_str())
    {
      SQLOrderBy_ptr orderBy = exprParser->parseOrderBy();
      // stmt->setOrderBy(orderBy);
    }

    if (lexer->token()->name->c_str() == Token::LIMIT.name->c_str())
    {
      SQLLimit_ptr limit = exprParser->parseLimit();
      // stmt->setLimit(limit);
    }

    // return stmt;
  }

  if (lexer->identifierEquals(make_string_ptr("TOPOLOGY")))
  {
    lexer->nextToken();
    // MySqlShowTopologyStatement* stmt = new MySqlShowTopologyStatement();

    if (lexer->token()->name->c_str() == Token::FROM.name->c_str())
    {
      lexer->nextToken();
    }
    // stmt->setName(exprParser->name());

    if (lexer->token()->name->c_str() == Token::WHERE.name->c_str())
    {
      lexer->nextToken();
      SQLExpr_ptr where = exprParser->getExpr();
      // stmt->setWhere(where);
    }

    if (lexer->token()->name->c_str() == Token::ORDER.name->c_str())
    {
      SQLOrderBy_ptr orderBy = exprParser->parseOrderBy();
      // stmt->setOrderBy(orderBy);
    }

    if (lexer->token()->name->c_str() == Token::LIMIT.name->c_str())
    {
      SQLLimit_ptr limit = exprParser->parseLimit();
      // stmt->setLimit(limit);
    }

    // stmt->setFull(full);

    // return stmt;
  }

  if (lexer->identifierEquals(FnvHash::Constants::PLANCACHE))
  {
    lexer->nextToken();

    if (lexer->identifierEquals(FnvHash::Constants::STATUS))
    {
      lexer->nextToken();
      // return new MySqlShowPlanCacheStatusStatement();
    }
    else if (lexer->identifierEquals(FnvHash::Constants::PLAN))
    {
      lexer->nextToken();
      // SQLSelect* select = this->createSQLSelectParser().select();
      // return new MySqlShowPlanCacheStatement(select);
    }
    else
    {
      throw new ParserException(make_string_ptr("TODO " + encode_util::UnicodeToUTF8(lexer->info())));
    }
  }

  if (lexer->identifierEquals(FnvHash::Constants::SLOW))
  {
    // MySqlShowSlowStatement* stmt = parserShowSlow();
    // stmt->setPhysical(BOOL::FALSE);
    // stmt->setFull(full);
    // return stmt;
  }

  if (lexer->identifierEquals(make_string_ptr("PHYSICAL_SLOW")))
  {
    // MySqlShowSlowStatement* stmt = parserShowSlow();
    // stmt->setPhysical(BOOL::TRUE);
    // stmt->setFull(full);
    // return stmt;
  }

  if (lexer->identifierEquals(FnvHash::Constants::QUERY_TASK))
  {
    lexer->nextToken();
    // SQLShowQueryTaskStatement* stmt = new SQLShowQueryTaskStatement();
    // stmt->setDbType(dbType);

    if (lexer->token()->name->c_str() == Token::FOR.name->c_str())
    {
      lexer->nextToken();
      // stmt->setUser(exprParser->getExpr());
    }

    if (lexer->token()->name->c_str() == Token::WHERE.name->c_str())
    {
      lexer->nextToken();
      SQLExpr_ptr where = this->exprParser->getExpr();
      // stmt->setWhere(where);
    }

    if (lexer->token()->name->c_str() == Token::ORDER.name->c_str())
    {
      SQLOrderBy_ptr orderBy = this->exprParser->parseOrderBy();
      // stmt->setOrderBy(orderBy);
    }

    if (lexer->token()->name->c_str() == Token::LIMIT.name->c_str())
    {
      SQLLimit_ptr limit = this->exprParser->parseLimit();
      // stmt->setLimit(limit);
    }

    if (full)
    {
      // stmt->setFull(BOOL::TRUE);
    }

    // return stmt;
  }
  if (lexer->identifierEquals(FnvHash::Constants::OUTLINES))
  {
    lexer->nextToken();
    // SQLShowOutlinesStatement* stmt = new SQLShowOutlinesStatement();
    // stmt->setDbType(dbType);

    if (lexer->token()->name->c_str() == Token::WHERE.name->c_str())
    {
      lexer->nextToken();
      SQLExpr_ptr where = this->exprParser->getExpr();
      // stmt->setWhere(where);
    }

    if (lexer->token()->name->c_str() == Token::ORDER.name->c_str())
    {
      SQLOrderBy_ptr orderBy = this->exprParser->parseOrderBy();
      // stmt->setOrderBy(orderBy);
    }

    if (lexer->token()->name->c_str() == Token::LIMIT.name->c_str())
    {
      SQLLimit_ptr limit = this->exprParser->parseLimit();
      // stmt->setLimit(limit);
    }

    // return stmt;
  }

  if (lexer->identifierEquals(FnvHash::Constants::RECYCLEBIN))
  {
    lexer->nextToken();

    // SQLShowRecylebinStatement* stmt = new SQLShowRecylebinStatement();
    // stmt->setDbType(dbType);
    // return stmt;
  }

  if (lexer->identifierEquals(FnvHash::Constants::TABLEGROUPS))
  {
    lexer->nextToken();

    // SQLShowTableGroupsStatement* stmt = parseShowTableGroups();

    // return stmt;
  }

  if (lexer->identifierEquals(FnvHash::Constants::CATALOGS))
  {
    lexer->nextToken();

    // SQLShowCatalogsStatement* stmt = new SQLShowCatalogsStatement();
    if (lexer->token()->name->c_str() == Token::LIKE.name->c_str())
    {
      lexer->nextToken();
      SQLExpr_ptr like = this->exprParser->getExpr();
      // stmt->setLike(like);
    }

    // return stmt;
  }

  if (lexer->identifierEquals(FnvHash::Constants::FUNCTIONS))
  {
    lexer->nextToken();

    // SQLShowFunctionsStatement* stmt = new SQLShowFunctionsStatement();
    if (lexer->token()->name->c_str() == Token::LIKE.name->c_str())
    {
      lexer->nextToken();
      SQLExpr_ptr like = this->exprParser->getExpr();
      // stmt->setLike(like);
    }

    // return stmt;
  }

  if (lexer->identifierEquals(FnvHash::Constants::SCHEMAS))
  {
    lexer->nextToken();

    // SQLShowDatabasesStatement* stmt = new SQLShowDatabasesStatement();
    // stmt->setPhysical(isPhysical);
    if (lexer->token()->name->c_str() == Token::IN.name->c_str() || lexer->token()->name->c_str() == Token::FROM.name->c_str())
    {
      lexer->nextToken();
      SQLName_ptr db = this->exprParser->name();
      // stmt->setDatabase(db);
    }

    if (full)
    {
      // stmt->setFull(BOOL::TRUE);
    }

    if (lexer->token()->name->c_str() == Token::LIKE.name->c_str())
    {
      lexer->nextToken();
      SQLExpr_ptr like = this->exprParser->getExpr();
      // stmt->setLike(like);
    }

    // return stmt;
  }

  if (lexer->identifierEquals(FnvHash::Constants::CONFIG))
  {
    lexer->nextToken();
    SQLName_ptr name = this->exprParser->name();
    // MySqlShowConfigStatement* stmt = new MySqlShowConfigStatement();
    // stmt->setName(name);
    // return stmt;
  }

  if (lexer->identifierEquals(FnvHash::Constants::USERS))
  {
    lexer->nextToken();
    // SQLShowUsersStatement* stmt = new SQLShowUsersStatement();
    // stmt->setDbType(dbType);
    // return stmt;
  }

  if (lexer->identifierEquals(FnvHash::Constants::PHYSICAL_PROCESSLIST))
  {
    lexer->nextToken();

    // MySqlShowPhysicalProcesslistStatement* stmt = new MySqlShowPhysicalProcesslistStatement();
    if (full)
    {
      // stmt->setFull(full);
    }
    // return stmt;
  }

  if (lexer->identifierEquals(make_string_ptr("MATERIALIZED")))
  {
    return parseShowMaterializedView();
  }

  if (lexer->token()->name->c_str() == Token::FULLTEXT.name->c_str())
  {
    lexer->nextToken();

    // MysqlShowFullTextStatement* stmt = new MysqlShowFullTextStatement();

    if (lexer->identifierEquals(FnvHash::Constants::CHARFILTERS))
    {
      // stmt->setType(FullTextType.CHARFILTER);
    }
    else if (lexer->identifierEquals(FnvHash::Constants::TOKENIZERS))
    {
      // stmt->setType(FullTextType.TOKENIZER);
    }
    else if (lexer->identifierEquals(FnvHash::Constants::TOKENFILTERS))
    {
      // stmt->setType(FullTextType.TOKENFILTER);
    }
    else if (lexer->identifierEquals(FnvHash::Constants::ANALYZERS))
    {
      // stmt->setType(FullTextType.ANALYZER);
    }
    else if (lexer->identifierEquals(FnvHash::Constants::DICTIONARIES))
    {
      // stmt->setType(FullTextType.DICTIONARY);
    }
    else
    {
      throw new ParserException(make_string_ptr("type of full text must be [CHARFILTERS/TOKENIZERS/TOKENFILTERS/ANALYZERS/DICTIONARYS] ."));
    }

    lexer->nextToken();

    // return stmt;
  }

  // DRDS GSI management syntax.
  if (isEnabled(SQLParserFeature_ptr(new SQLParserFeature(&SQLParserFeature::DRDSAsyncDDL))) && lexer->identifierEquals(make_string_ptr("METADATA")))
  {
    lexer->nextToken();

    if (Token::LOCK == *lexer->token() || lexer->identifierEquals(make_string_ptr("LOCKS")))
    {
      lexer->nextToken();

      // DrdsShowMetadataLock* stmt = new DrdsShowMetadataLock();
      if (Token::SEMI == *lexer->token() || Token::XEOF == *lexer->token())
      {
        // return stmt;
      }
      else
      {
        // stmt->setSchemaName(this->exprParser->name());
        // return stmt;
      }
    }
    else
    {
      throw new ParserException(make_string_ptr("syntax error, expect LOCK/LOCKS, actual " + *lexer->token()->getName() + ", " + encode_util::UnicodeToUTF8(lexer->info())));
    }
  }

  // MySqlShowSlaveHostsStatement

  throw new ParserException(make_string_ptr("TODO " + encode_util::UnicodeToUTF8(lexer->info())));
}

// MySqlShowStatusStatement* MySqlStatementParser::parseShowStatus() {
//     MySqlShowStatusStatement* stmt = new MySqlShowStatusStatement();

//     if (lexer->token()->name->c_str() == Token::LIKE.name->c_str()) {
//         lexer->nextToken();
//         SQLExpr_ptr like = exprParser->getExpr();
//         stmt->setLike(like);
//     }

//     if (lexer->token()->name->c_str() == Token::WHERE.name->c_str()) {
//         lexer->nextToken();
//         SQLExpr_ptr where = exprParser->getExpr();
//         stmt->setWhere(where);
//     }

//     return stmt;
// }

// MySqlShowSlowStatement* MySqlStatementParser::parserShowSlow() {
//     lexer->nextToken();
//     MySqlShowSlowStatement* stmt = new MySqlShowSlowStatement();

//     if (lexer->token()->name->c_str() == Token::WHERE.name->c_str()) {
//         lexer->nextToken();
//         SQLExpr_ptr where = exprParser->getExpr();
//         stmt->setWhere(where);
//     }

//     if (lexer->token()->name->c_str() == Token::ORDER.name->c_str()) {
//         SQLOrderBy* orderBy = exprParser->parseOrderBy();
//         stmt->setOrderBy(orderBy);
//     }

//     if (lexer->token()->name->c_str() == Token::LIMIT.name->c_str()) {
//         SQLLimit* limit = exprParser->parseLimit();
//         stmt->setLimit(limit);
//     }

//     return stmt;
// }

// MySqlShowWarningsStatement* MySqlStatementParser::parseShowWarnings() {
//     MySqlShowWarningsStatement stmt = new MySqlShowWarningsStatement();

//     stmt->setLimit(this->exprParser->parseLimit());

//     return stmt;
// }

// SQLStartTransactionStatement* MySqlStatementParser::parseStart() {
//     acceptIdentifier("START");
//     acceptIdentifier("TRANSACTION");

//     SQLStartTransactionStatement* stmt = new SQLStartTransactionStatement(dbType);

//     if (lexer->token()->name->c_str() == Token::WITH.name->c_str()) {
//         lexer->nextToken();
//         acceptIdentifier("CONSISTENT");
//         acceptIdentifier("SNAPSHOT");
//         stmt->setConsistentSnapshot(BOOL::TRUE);
//     }

//     if (lexer->token()->name->c_str() == Token::BEGIN.name->c_str()) {
//         lexer->nextToken();
//         stmt->setBegin(BOOL::TRUE);
//         if (lexer->identifierEquals(make_string_ptr("WORK"))) {
//             lexer->nextToken();
//             stmt->setWork(BOOL::TRUE);
//         }
//     }

//     if (lexer->token()->name->c_str() == Token::HINT.name->c_str()) {
//         stmt->setHints(this->exprParser->parseHints());
//     }

//     if (lexer->identifierEquals(FnvHash::Constants::ISOLATION)) {
//         lexer->nextToken();
//         acceptIdentifier("LEVEL");

//         if (lexer->identifierEquals(FnvHash::Constants::READ)) {
//             lexer->nextToken();
//             if (lexer->identifierEquals(FnvHash::Constants::UNCOMMITTED)) {
//                 lexer->nextToken();
//                 stmt->setIsolationLevel(SQLStartTransactionStatement.IsolationLevel.READ_UNCOMMITTED);
//             } else if (lexer->identifierEquals(FnvHash::Constants::COMMITTED)) {
//                 lexer->nextToken();
//                 stmt->setIsolationLevel(SQLStartTransactionStatement.IsolationLevel.READ_COMMITTED);
//             } else {
//                 throw new ParserException(lexer->info());
//             }
//         } else if (lexer->identifierEquals(FnvHash::Constants::REPEATABLE)) {
//             lexer->nextToken();
//             acceptIdentifier("READ");
//             stmt->setIsolationLevel(SQLStartTransactionStatement.IsolationLevel.REPEATABLE_READ);
//         } else if (lexer->identifierEquals(FnvHash::Constants::SERIALIZABLE)) {
//             lexer->nextToken();
//             stmt->setIsolationLevel(SQLStartTransactionStatement.IsolationLevel.SERIALIZABLE);
//         } else {
//             throw new ParserException(lexer->info());
//         }
//     }

//     if (lexer->identifierEquals(FnvHash::Constants::READ)) {
//         lexer->nextToken();
//         acceptIdentifier("ONLY");
//         stmt->setReadOnly(BOOL::TRUE);
//     }

//     return stmt;
// }

SQLStatement_ptr MySqlStatementParser::parseRollback()
{
  acceptIdentifier("ROLLBACK");

  // DRDS async DDL.
  if (isEnabled(SQLParserFeature_ptr(new SQLParserFeature(&SQLParserFeature::DRDSAsyncDDL))) && lexer->identifierEquals(make_string_ptr("DDL")))
  {
    // ROLLBACK DDL <job_id> [, <job_id>] ...
    lexer->nextToken();
    // DrdsRollbackDDLJob* stmt = new DrdsRollbackDDLJob();
    while (BOOL::TRUE)
    {
      // stmt->addJobId(lexer->integerValue().longValue());
      accept(Token::LITERAL_INT);
      if (Token::COMMA == *lexer->token())
      {
        lexer->nextToken();
      }
      else if (lexer->token()->name->c_str() == Token::XEOF.name->c_str() || lexer->token()->name->c_str() == Token::SEMI.name->c_str())
      {
        break;
      }
      else
      {
        throw new ParserException(make_string_ptr("syntax error, expect job id, actual " + *lexer->token()->getName() + ", " + encode_util::UnicodeToUTF8(lexer->info())));
      }
    }
    // return stmt;
  }

  // SQLRollbackStatement* stmt = new SQLRollbackStatement();

  if (lexer->identifierEquals(make_string_ptr("WORK")))
  {
    lexer->nextToken();
  }

  if (lexer->token()->name->c_str() == Token::AND.name->c_str())
  {
    lexer->nextToken();
    if (lexer->token()->name->c_str() == Token::NOT.name->c_str())
    {
      lexer->nextToken();
      acceptIdentifier(CHAIN);
      // stmt->setChain(BOOL_ptr.FALSE);
    }
    else
    {
      acceptIdentifier(CHAIN);
      // stmt->setChain(BOOL::TRUE);
    }
  }

  if (lexer->token()->name->c_str() == Token::TO.name->c_str())
  {
    lexer->nextToken();

    if (lexer->identifierEquals(make_string_ptr("SAVEPOINT")))
    {
      lexer->nextToken();
    }

    // stmt->setTo(this->exprParser->name());
  }

  // return stmt;
}

SQLStatement_ptr MySqlStatementParser::parseCommit()
{
  acceptIdentifier("COMMIT");

  // SQLCommitStatement* stmt = new SQLCommitStatement();

  if (lexer->identifierEquals(make_string_ptr("WORK")))
  {
    lexer->nextToken();
    // stmt->setWork(BOOL::TRUE);
  }

  if (lexer->token()->name->c_str() == Token::AND.name->c_str())
  {
    lexer->nextToken();
    if (lexer->token()->name->c_str() == Token::NOT.name->c_str())
    {
      lexer->nextToken();
      acceptIdentifier(CHAIN);
      // stmt->setChain(BOOL_ptr.FALSE);
    }
    else
    {
      acceptIdentifier(CHAIN);
      // stmt->setChain(BOOL::TRUE);
    }
  }

  // return stmt;
}

// SQLReplaceStatement* MySqlStatementParser::parseReplace() {
//     SQLReplaceStatement* stmt = new SQLReplaceStatement();
//     stmt->setDbType(DbType::mysql);

//     std::list<SQLCommentHint*> list = new Arraystd::list<SQLCommentHint*>();

//     while (lexer->token()->name->c_str() == Token::HINT.name->c_str()) {
//         this->exprParser->parseHints(list);
//     }
//     stmt->setHeadHints(list);

//     accept(Token::REPLACE);
//     while (lexer->token()->name->c_str() == Token::HINT.name->c_str()) {
//         this->exprParser->parseHints(stmt->getHints());
//     }
//     if (lexer->token()->name->c_str() == Token::COMMENT.name->c_str()) {
//         lexer->nextToken();
//     }

//     if (lexer->identifierEquals(FnvHash::Constants::LOW_PRIORITY)) {
//         stmt->setLowPriority(BOOL::TRUE);
//         lexer->nextToken();
//     }

//     if (lexer->identifierEquals(FnvHash::Constants::DELAYED)) {
//         stmt->setDelayed(BOOL::TRUE);
//         lexer->nextToken();
//     }

//     if (lexer->token()->name->c_str() == Token::INTO.name->c_str()) {
//         lexer->nextToken();
//     }

//     SQLName_ptr  tableName = exprParser->name();
//     stmt->setTableName(tableName);

//     if (lexer->token()->name->c_str() == Token::PARTITION.name->c_str()) {
//         lexer->nextToken();
//         accept(Token::LPAREN);
//         for (; ; ) {
//             SQLAssignItem* ptExpr = new SQLAssignItem();
//             ptExpr.setTarget(this->exprParser->name());
//             if (lexer->token()->name->c_str() == Token::EQ.name->c_str()) {
//                 lexer->nextToken();
//                 SQLExpr_ptr ptValue = this->exprParser->getExpr();
//                 ptExpr.setValue(ptValue);
//             }
//             stmt->addPartition(ptExpr);
//             if (lexer->token()->name->c_str() != Token::COMMA) {
//                 break;
//             } else {
//                 lexer->nextToken();
//             }
//         }
//         accept(Token::RPAREN);
//     }

//     if (lexer->token()->name->c_str() == Token::LPAREN.name->c_str()) {
//         lexer->nextToken();
//         if (lexer->token()->name->c_str() == Token::SELECT.name->c_str()) {
//             SQLQueryExpr queryExpr = (SQLQueryExpr) this->exprParser->getExpr();
//             stmt->setQuery(queryExpr);
//         } else {
//             this->exprParser->exprstd::list(stmt->getColumns(), stmt);
//         }
//         accept(Token::RPAREN);
//     }

//     if (lexer->token()->name->c_str() == Token::VALUES || lexer->identifierEquals("VALUE")) {
//         lexer->nextToken();

//         parseValueClause(stmt->getValuesList(), nullptr, 0, stmt);
//     } else if (lexer->token()->name->c_str() == Token::SELECT.name->c_str()) {
//         SQLQueryExpr* queryExpr = (SQLQueryExpr) this->exprParser->getExpr();
//         stmt->setQuery(queryExpr);
//     } else if (lexer->token()->name->c_str() == Token::SET.name->c_str()) {
//         lexer->nextToken();

//         SQLInsertStatement.ValuesClause values = new SQLInsertStatement.ValuesClause();
//         values.setParent(stmt);
//         stmt->getValuesList().add(values);
//         for (; ; ) {
//             stmt->addColumn(this->exprParser->name());
//             if (lexer->token()->name->c_str() == Token::COLONEQ) {
//                 lexer->nextToken();
//             } else {
//                 accept(Token::EQ);
//             }
//             values.addValue(this->exprParser->getExpr());

//             if (lexer->token()->name->c_str() == (Token::COMMA)) {
//                 lexer->nextToken();
//                 continue;
//             }

//             break;
//         }
//     } else if (lexer->token()->name->c_str() == Token::LPAREN.name->c_str()) {
//         SQLSelect* select = this->createSQLSelectParser().select();
//         SQLQueryExpr* queryExpr = new SQLQueryExpr(select);
//         stmt->setQuery(queryExpr);
//     }

//     return stmt;
// }

SQLStatement_ptr MySqlStatementParser::parseLoad()
{
  acceptIdentifier("LOAD");

  if (lexer->identifierEquals(make_string_ptr("DATA")))
  {
    // SQLStatement_ptr  stmt = parseLoadDataInFile();
    // return stmt;
  }

  if (lexer->identifierEquals(make_string_ptr("XML")))
  {
    // SQLStatement_ptr  stmt = parseLoadXml();
    // return stmt;
  }

  throw new ParserException(make_string_ptr("TODO. " + encode_util::UnicodeToUTF8(lexer->info())));
}

// MySqlLoadXmlStatement* MySqlStatementParser::parseLoadXml() {
//     acceptIdentifier("XML");

//     MySqlLoadXmlStatement* stmt = new MySqlLoadXmlStatement();

//     if (lexer->identifierEquals(FnvHash::Constants::LOW_PRIORITY)) {
//         stmt->setLowPriority(BOOL::TRUE);
//         lexer->nextToken();
//     }

//     if (lexer->identifierEquals("CONCURRENT")) {
//         stmt->setConcurrent(BOOL::TRUE);
//         lexer->nextToken();
//     }

//     if (lexer->identifierEquals(LOCAL)) {
//         stmt->setLocal(BOOL::TRUE);
//         lexer->nextToken();
//     }

//     acceptIdentifier("INFILE");

//     SQLLiteralExpr fileName = (SQLLiteralExpr) exprParser->getExpr();
//     stmt->setFileName(fileName);

//     if (lexer->token()->name->c_str() == Token::REPLACE) {
//         stmt->setReplicate(BOOL::TRUE);
//         lexer->nextToken();
//     }

//     if (lexer->identifierEquals(FnvHash::Constants::IGNORE)) {
//         stmt->setIgnore(BOOL::TRUE);
//         lexer->nextToken();
//     }

//     accept(Token::INTO);
//     accept(Token::TABLE);

//     SQLName_ptr  tableName = exprParser->name();
//     stmt->setTableName(tableName);

//     if (lexer->identifierEquals(FnvHash::Constants::CHARACTER)) {
//         lexer->nextToken();
//         accept(Token::SET);

//         if (lexer->token()->name->c_str() != Token::LITERAL_CHARS) {
//             throw new ParserException("syntax error, illegal charset. " + lexer->info());
//         }

//         string_ptr  charset = lexer->stringVal();
//         lexer->nextToken();
//         stmt->setCharset(charset);
//     }

//     if (lexer->identifierEquals("ROWS")) {
//         lexer->nextToken();
//         acceptIdentifier("IDENTIFIED");
//         accept(Token::BY);
//         SQLExpr_ptr rowsIdentifiedBy = exprParser->getExpr();
//         stmt->setRowsIdentifiedBy(rowsIdentifiedBy);
//     }

//     if (lexer->identifierEquals(FnvHash::Constants::IGNORE)) {
//         throw new ParserException("TODO. " + lexer->info());
//     }

//     if (lexer->token()->name->c_str() == Token::SET.name->c_str()) {
//         throw new ParserException("TODO. " + lexer->info());
//     }

//     return stmt;
// }

// MySqlLoadDataInFileStatement* MySqlStatementParser::parseLoadDataInFile() {
//     acceptIdentifier("DATA");

//     MySqlLoadDataInFileStatement stmt = new MySqlLoadDataInFileStatement();

//     if (lexer->identifierEquals(FnvHash::Constants::LOW_PRIORITY)) {
//         stmt->setLowPriority(BOOL::TRUE);
//         lexer->nextToken();
//     }

//     if (lexer->identifierEquals("CONCURRENT")) {
//         stmt->setConcurrent(BOOL::TRUE);
//         lexer->nextToken();
//     }

//     if (lexer->identifierEquals(LOCAL)) {
//         stmt->setLocal(BOOL::TRUE);
//         lexer->nextToken();
//     }

//     acceptIdentifier("INFILE");

//     SQLLiteralExpr fileName = (SQLLiteralExpr) exprParser->getExpr();
//     stmt->setFileName(fileName);

//     if (lexer->token()->name->c_str() == Token::REPLACE) {
//         stmt->setReplicate(BOOL::TRUE);
//         lexer->nextToken();
//     }

//     if (lexer->identifierEquals(FnvHash::Constants::IGNORE)) {
//         stmt->setIgnore(BOOL::TRUE);
//         lexer->nextToken();
//     }

//     accept(Token::INTO);
//     accept(Token::TABLE);

//     SQLName_ptr  tableName = exprParser->name();
//     stmt->setTableName(tableName);

//     if (lexer->identifierEquals(FnvHash::Constants::CHARACTER)) {
//         lexer->nextToken();
//         accept(Token::SET);

//         if (lexer->token()->name->c_str() != Token::LITERAL_CHARS) {
//             throw new ParserException("syntax error, illegal charset. " + lexer->info());
//         }

//         string_ptr  charset = lexer->stringVal();
//         lexer->nextToken();
//         stmt->setCharset(charset);
//     }

//     if (lexer->identifierEquals(make_string_ptr("FIELDS")) || lexer->identifierEquals(make_string_ptr("COLUMNS"))) {
//         lexer->nextToken();
//         if (lexer->identifierEquals("TERMINATED")) {
//             lexer->nextToken();
//             accept(Token::BY);

//             if (lexer->token()->name->c_str() == Token::LITERAL_CHARS) {
//                 stmt->setColumnsTerminatedBy(new SQLCharExpr(lexer->stringVal()));
//                 lexer->nextToken();
//             } else {
//                 SQLExpr_ptr primary = this->exprParser->primary();
//                 if (primary instanceof SQLHexExpr) {
//                     stmt->setColumnsTerminatedBy((SQLHexExpr) primary);
//                 } else {
//                     throw new ParserException("invalid expr for columns terminated : " + primary);
//                 }
//             }
//         }

//         if (lexer->identifierEquals("OPTIONALLY")) {
//             stmt->setColumnsEnclosedOptionally(BOOL::TRUE);
//             lexer->nextToken();
//         }

//         if (lexer->identifierEquals("ENCLOSED")) {
//             lexer->nextToken();
//             accept(Token::BY);
//             stmt->setColumnsEnclosedBy(new SQLCharExpr(lexer->stringVal()));
//             lexer->nextToken();
//         }

//         if (lexer->identifierEquals("ESCAPED")) {
//             lexer->nextToken();
//             accept(Token::BY);
//             stmt->setColumnsEscaped(new SQLCharExpr(lexer->stringVal()));
//             lexer->nextToken();
//         }
//     }

//     if (lexer->identifierEquals("LINES")) {
//         lexer->nextToken();
//         if (lexer->identifierEquals("STARTING")) {
//             lexer->nextToken();
//             accept(Token::BY);

//             if (lexer->token()->name->c_str() == Token::LITERAL_CHARS) {
//                 stmt->setLinesStartingBy(new SQLCharExpr(lexer->stringVal()));
//                 lexer->nextToken();
//             } else {
//                 SQLExpr_ptr primary = this->exprParser->primary();
//                 if (primary instanceof SQLHexExpr) {
//                     stmt->setLinesStartingBy((SQLHexExpr) primary);
//                 } else {
//                     throw new ParserException("invalid expr for lines starting : " + primary);
//                 }
//             }
//         }

//         if (lexer->identifierEquals("TERMINATED")) {
//             lexer->nextToken();
//             accept(Token::BY);
//             if (lexer->token()->name->c_str() == Token::LITERAL_CHARS) {
//                 stmt->setLinesTerminatedBy(new SQLCharExpr(lexer->stringVal()));
//                 lexer->nextToken();
//             } else {
//                 SQLExpr_ptr primary = this->exprParser->primary();
//                 if (primary instanceof SQLHexExpr) {
//                     stmt->setLinesTerminatedBy((SQLHexExpr) primary);
//                 } else {
//                     throw new ParserException("invalid expr for lines terminated : " + primary);
//                 }
//             }
//         }
//     }

//     if (lexer->identifierEquals(FnvHash::Constants::IGNORE)) {
//         lexer->nextToken();
//         stmt->setIgnoreLinesNumber(this->exprParser->getExpr());
//         acceptIdentifier("LINES");
//     }

//     if (lexer->token()->name->c_str() == Token::LPAREN.name->c_str()) {
//         lexer->nextToken();
//         this->exprParser->exprstd::list(stmt->getColumns(), stmt);
//         accept(Token::RPAREN);
//     }

//     if (lexer->token()->name->c_str() == Token::SET.name->c_str()) {
//         lexer->nextToken();
//         this->exprParser->exprstd::list(stmt->getSetstd::list(), stmt);
//     }

//     return stmt;

// }

// MySqlPrepareStatement* MySqlStatementParser::parsePrepare() {
//     acceptIdentifier("PREPARE");

//     SQLName_ptr  name = exprParser->name();
//     accept(Token::FROM);
//     SQLExpr_ptr from = exprParser->getExpr();

//     return new MySqlPrepareStatement(name, from);
// }

// MySqlExecuteStatement* MySqlStatementParser::parseExecute() {
//     MySqlExecuteStatement stmt = new MySqlExecuteStatement();

//     SQLName_ptr  statementName = exprParser->name();
//     stmt->setStatementName(statementName);

//     if (lexer->identifierEquals("USING")) {
//         lexer->nextToken();
//         exprParser->exprstd::list(stmt->getParameters(), stmt);
//     } else if (lexer->token()->name->c_str() == Token::IDENTIFIER.name->c_str()) {
//         exprParser->exprstd::list(stmt->getParameters(), stmt);
//     }
//     return stmt;
// }

// MySqlExecuteForAdsStatement* MySqlStatementParser::parseExecuteForAds() {
//     MySqlExecuteForAdsStatement stmt = new MySqlExecuteForAdsStatement();
//     stmt->setAction(exprParser->name());
//     stmt->setRole(exprParser->name());

//     stmt->setTargetId(exprParser->charExpr());

//     if (lexer->token()->name->c_str() == Token::IDENTIFIER.name->c_str()) {
//         stmt->setStatus(exprParser->name());
//     }
//     return stmt;
// }

// MysqlDeallocatePrepareStatement* MySqlStatementParser::parseDeallocatePrepare() {
//     acceptIdentifier("DEALLOCATE");
//     acceptIdentifier("PREPARE");

//     MysqlDeallocatePrepareStatement stmt = new MysqlDeallocatePrepareStatement();
//     SQLName_ptr  statementName = exprParser->name();
//     stmt->setStatementName(statementName);

//     return stmt;
// }

// SQLInsertStatement_ptr MySqlStatementParser::parseInsert()
SQLStatement_ptr MySqlStatementParser::parseInsert()
{
  LOG_INFO << "in parseInsert";
  MySqlInsertStatement_ptr stmt = MySqlInsertStatement_ptr(new MySqlInsertStatement());

  SQLName_ptr tableName = nullptr;
  if (lexer->token()->name->c_str() == Token::INSERT.name->c_str())
  {
    lexer->nextToken();

    for (;;)
    {
      if (lexer->token()->name->c_str() == Token::IDENTIFIER.name->c_str())
      {
        long hash = lexer->hashLCase();

        if (hash == FnvHash::Constants::LOW_PRIORITY)
        {
          stmt->setLowPriority(BOOL::TRUE);
          lexer->nextToken();
          continue;
        }

        if (hash == FnvHash::Constants::DELAYED)
        {
          stmt->setDelayed(BOOL::TRUE);
          lexer->nextToken();
          continue;
        }

        if (hash == FnvHash::Constants::HIGH_PRIORITY)
        {
          stmt->setHighPriority(BOOL::TRUE);
          lexer->nextToken();
          continue;
        }

        if (hash == FnvHash::Constants::IGNORE)
        {
          stmt->setIgnore(BOOL::TRUE);
          lexer->nextToken();
          continue;
        }

        if (hash == FnvHash::Constants::ROLLBACK_ON_FAIL)
        {
          stmt->setRollbackOnFail(BOOL::TRUE);
          lexer->nextToken();
          continue;
        }
      }

      break;
    }

    if (lexer->token()->name->c_str() == Token::HINT.name->c_str())
    {
      SQLCommentHint_list_ptr hints = this->exprParser->parseHints();
      stmt->setHints(hints);
    }

    if (lexer->token()->name->c_str() == Token::INTO.name->c_str())
    {
      lexer->nextToken();
      if (lexer->token()->name->c_str() == Token::TABLE.name->c_str())
      {
        lexer->nextToken();
      }
    }
    else if (lexer->identifierEquals(FnvHash::Constants::OVERWRITE))
    {
      lexer->nextToken();
      stmt->setOverwrite(BOOL::TRUE);
      if (lexer->token()->name->c_str() == Token::TABLE.name->c_str())
      {
        lexer->nextToken();
      }
      else if (lexer->token()->name->c_str() == Token::INTO.name->c_str())
      {
        lexer->nextToken();
      }
    }

    if (lexer->token()->name->c_str() == Token::LINE_COMMENT.name->c_str())
    {
      lexer->nextToken();
    }

    if (lexer->token()->name->c_str() == Token::FULLTEXT.name->c_str())
    {
      lexer->nextToken();
      if (lexer->identifierEquals(FnvHash::Constants::DICTIONARY))
      {
        lexer->nextToken();
        stmt->setFulltextDictionary(BOOL::TRUE);
      }
    }

    tableName = this->exprParser->name();
    stmt->setTableName(tableName);

    if (lexer->token()->name->c_str() == Token::HINT.name->c_str())
    {
      string_ptr comment = make_string_ptr("/*" + encode_util::UnicodeToUTF8(*lexer->stringVal()) + "*/");
      lexer->nextToken();
      stmt->getTableSource()->addAfterComment(comment);
    }

    if (lexer->token()->name->c_str() == Token::IDENTIFIER.name->c_str() &&
        !lexer->identifierEquals(FnvHash::Constants::VALUE))
    {
      stmt->setAlias(make_string_ptr(encode_util::UnicodeToUTF8(*lexer->stringVal())));
      lexer->nextToken();
    }

    if (lexer->token()->name->c_str() == Token::WITH.name->c_str())
    {
      SQLSelectStatement_ptr withStmt = std::dynamic_pointer_cast<SQLSelectStatement>(parseWith());
      stmt->setQuery(withStmt->getSelect());
    }

    if (lexer->token()->name->c_str() == Token::PARTITION.name->c_str())
    {
      lexer->nextToken();
      accept(Token::LPAREN);
      for (;;)
      {
        SQLAssignItem_ptr ptExpr = SQLAssignItem_ptr(new SQLAssignItem());
        ptExpr->setTarget(this->exprParser->name());
        if (lexer->token()->name->c_str() == Token::EQ.name->c_str())
        {
          lexer->nextToken();
          SQLExpr_ptr ptValue = this->exprParser->getExpr();
          ptExpr->setValue(ptValue);
        }
        stmt->addPartition(ptExpr);
        if (lexer->token()->name->c_str() != Token::COMMA.name->c_str())
        {
          break;
        }
        else
        {
          lexer->nextToken();
        }
      }
      accept(Token::RPAREN);

      if (lexer->token()->name->c_str() == Token::IF.name->c_str())
      {
        lexer->nextToken();
        accept(Token::NOT);
        accept(Token::EXISTS);

        stmt->setIfNotExists(BOOL::TRUE);
      }
    }
  }

  int columnSize = 0;
  SQLColumnDefinition_list_ptr columnDefinitionList = nullptr;

  LOG_INFO << "lexer->token->name:" << lexer->token()->getName()->c_str() << ",lexer->stringVal_:" << encode_util::UnicodeToUTF8(lexer->stringVal_);
  if (lexer->token()->name->c_str() == Token::LPAREN.name->c_str())
  {
    LOG_INFO << "lexer->token->name: Token::LPAREN";
    BOOL_ptr useInsertColumnsCache = lexer->isEnabled(SQLParserFeature_ptr(new SQLParserFeature(&SQLParserFeature::UseInsertColumnsCache)));
    InsertColumnsCache_ptr insertColumnsCache = nullptr;

    long tableNameHash = 0;
    InsertColumnsCache_Entry_ptr cachedColumns = nullptr;
    LOG_INFO << "useInsertColumnsCache:" << useInsertColumnsCache;
    if (useInsertColumnsCache)
    {
      insertColumnsCache = this->insertColumnsCache;
      if (insertColumnsCache == nullptr)
      {
        insertColumnsCache = InsertColumnsCache::global;
      }

      if (tableName != nullptr)
      {
        tableNameHash = tableName->nameHashCode64();
        cachedColumns = insertColumnsCache->get(tableNameHash);
      }
    }

    SchemaObject_ptr tableObject = nullptr;
    int pos = lexer->pos();
    if (cachedColumns != nullptr &&
        StringUtils::startWith(make_string_ptr(encode_util::UnicodeToUTF8(lexer->getSource())), cachedColumns->columnsString, pos))
    {
      if (!lexer->isEnabled(SQLParserFeature_ptr(new SQLParserFeature(&SQLParserFeature::OptimizedForParameterized))))
      {
        SQLExpr_list_ptr columns = stmt->getColumns();
        SQLExpr_list_ptr cachedColumns2 = cachedColumns->columns;
        auto it_cachedColumns2 = cachedColumns2->begin();
        for (int i = 0, size = cachedColumns2->size(); i < size; i++)
        {
          std::advance(it_cachedColumns2, i);
          columns->push_back(std::dynamic_pointer_cast<SQLExpr>((*it_cachedColumns2)->clone()));
        }
      }
      stmt->setColumnsString(cachedColumns->columnsFormattedString, cachedColumns->columnsFormattedStringHash);
      int p2 = pos + cachedColumns->columnsString->length();
      lexer->reset(p2);
      lexer->nextToken();
    }
    else
    {
      Lexer_SavePoint_ptr mark = lexer->mark();
      LOG_INFO << "goto nextToken";
      lexer->nextToken();
      if (lexer->token()->name->c_str() == Token::SELECT.name->c_str())
      {
        lexer->reset(mark);
        SQLSelect_ptr select = this->exprParser->createSelectParser()->select();
        select->setParent(stmt);
        stmt->setQuery(select);
      }
      else
      {
        if (repository != nullptr && lexer->isEnabled(SQLParserFeature_ptr(new SQLParserFeature(&SQLParserFeature::InsertValueCheckType))))
        {
          tableObject = repository->findTable(tableName->nameHashCode64());
        }

        if (tableObject != nullptr)
        {
          columnDefinitionList = std::make_shared<std::list<SQLColumnDefinition_ptr>>();
        }

        SQLExpr_list_ptr columns = stmt->getColumns();

        LOG_INFO << "lexer->token->name:" << lexer->token()->getName()->c_str() << ",lexer->stringVal_:" << encode_util::UnicodeToUTF8(lexer->stringVal_);
        if (lexer->token()->name->c_str() != Token::RPAREN.name->c_str())
        {
          LOG_INFO << "lexer->token->name: != Token::RPAREN";
          for (;;)
          {
            string_ptr identName;
            long hash;

            Token_ptr token = lexer->token();
            LOG_INFO << "lexer->token->name:" << lexer->token()->getName()->c_str() << ",lexer->stringVal_:" << encode_util::UnicodeToUTF8(lexer->stringVal_);
            if (token->name == Token::IDENTIFIER.name)
            {
              identName = make_string_ptr(encode_util::UnicodeToUTF8(*lexer->stringVal()));
              hash = lexer->hashLCase();
            }
            else if (token->name == Token::LITERAL_CHARS.name)
            {
              if (lexer->isEnabled(SQLParserFeature_ptr(new SQLParserFeature(&SQLParserFeature::IgnoreNameQuotes))))
              {
                identName = make_string_ptr(encode_util::UnicodeToUTF8(*lexer->stringVal()));
              }
              else
              {
                identName = make_string_ptr('\'' + encode_util::UnicodeToUTF8(*lexer->stringVal()) + '\'');
              }
              hash = 0;
            }
            else if (token->name == Token::LITERAL_ALIAS.name)
            {
              identName = make_string_ptr(encode_util::UnicodeToUTF8(*lexer->stringVal()));
              if (lexer->isEnabled(SQLParserFeature_ptr(new SQLParserFeature(&SQLParserFeature::IgnoreNameQuotes))))
              {
                identName = SQLUtils::normalize(identName, dbType);
              }
              hash = 0;
            }
            else
            {
              identName = make_string_ptr(encode_util::UnicodeToUTF8(*lexer->stringVal()));
              hash = 0;
            }

            lexer->nextTokenComma();
            SQLExpr_ptr expr = SQLIdentifierExpr_ptr(new SQLIdentifierExpr(identName, hash));
            while (lexer->token()->name->c_str() == Token::DOT.name->c_str())
            {
              lexer->nextToken();
              string_ptr propertyName = make_string_ptr(encode_util::UnicodeToUTF8(*lexer->stringVal()));
              lexer->nextToken();
              expr = SQLPropertyExpr_ptr(new SQLPropertyExpr(expr, propertyName));
            }

            expr->setParent(stmt);
            columns->push_back(expr);
            columnSize++;

            if (tableObject != nullptr)
            {
              SQLColumnDefinition_ptr columnDefinition = tableObject->findColumn(hash);
              columnDefinitionList->push_back(columnDefinition);
            }

            if (lexer->token()->name->c_str() == Token::COMMA.name->c_str())
            {
              lexer->nextTokenIdent();
              continue;
            }

            break;
          }

          columnSize = stmt->getColumns()->size();
          LOG_INFO << "columnSize:" << columnSize;

          if (insertColumnsCache != nullptr && tableName != nullptr)
          {
            LOG_INFO << "insertColumnsCache != nullptr && tableName != nullptr";
            string_ptr columnsString = make_string_ptr(encode_util::UnicodeToUTF8(lexer->subString(pos, lexer->pos() - pos)));

            SQLExpr_list_ptr clonedColumns = std::make_shared<std::list<SQLExpr_ptr>>();
            auto it_columns = columns->begin();
            for (int i = 0; i < columns->size(); i++)
            {
              std::advance(it_columns, i);
              clonedColumns->push_back(std::dynamic_pointer_cast<SQLExpr>((*it_columns)->clone()));
            }

            std::stringstream buf;
            SQLASTOutputVisitor_ptr outputVisitor = SQLUtils::createOutputVisitor(&buf, dbType);
            outputVisitor->printInsertColumns(columns);

            string_ptr formattedColumnsString = make_string_ptr(buf.str());
            long columnsFormattedStringHash = FnvHash::fnv1a_64_lower(formattedColumnsString);

            insertColumnsCache->put(tableName->hashCode64(), columnsString, formattedColumnsString, clonedColumns);
            stmt->setColumnsString(formattedColumnsString, columnsFormattedStringHash);
          }
        }
        accept(Token::RPAREN);
      }
    }
  }

  SQLCommentHint_list_ptr commentHints = nullptr;

  LOG_INFO << "lexer->token->name:" << lexer->token()->getName()->c_str();
  LOG_INFO << "lexer->stringVal_:" << encode_util::UnicodeToUTF8(lexer->stringVal_);
  if (lexer->token()->name->c_str() == Token::HINT.name->c_str())
  {
    commentHints = this->exprParser->parseHints();
  }
  else if (lexer->token()->name->c_str() == Token::LINE_COMMENT.name->c_str())
  {
    lexer->nextToken();
  }

  LOG_INFO << "lexer->token->name:" << lexer->token()->getName()->c_str();
  LOG_INFO << "lexer->stringVal_:" << encode_util::UnicodeToUTF8(lexer->stringVal_);
  if (lexer->token()->name->c_str() == Token::VALUES.name->c_str() || lexer->identifierEquals(FnvHash::Constants::VALUE))
  {
    lexer->nextTokenLParen();
    LOG_INFO << "lexer->token->name:" << lexer->token()->getName()->c_str();
    LOG_INFO << "lexer->stringVal_:" << encode_util::UnicodeToUTF8(lexer->stringVal_);
    if (lexer->isEnabled(SQLParserFeature_ptr(new SQLParserFeature(&SQLParserFeature::InsertReader))))
    {
      LOG_INFO << "return stmt";
      return stmt;
    }

    if (lexer->isEnabled(SQLParserFeature_ptr(new SQLParserFeature(&SQLParserFeature::InsertValueNative))))
    {
      LOG_INFO << "goto parseValueClauseNative";
      parseValueClauseNative(stmt->getValuesList(), columnDefinitionList, columnSize, stmt);
    }
    else
    {
      LOG_INFO << "goto parseValueClause";
      parseValueClause(stmt->getValuesList(), columnDefinitionList, columnSize, stmt);
    }
  }
  else if (lexer->token()->name->c_str() == Token::SET.name->c_str())
  {
    lexer->nextToken();

    SQLInsertStatement_ValuesClause_ptr values = SQLInsertStatement_ValuesClause_ptr(new SQLInsertStatement_ValuesClause());
    stmt->addValueCause(values);

    for (;;)
    {
      SQLName_ptr name = this->exprParser->name();
      stmt->addColumn(name);
      if (lexer->token()->name->c_str() == Token::EQ.name->c_str())
      {
        lexer->nextToken();
      }
      else
      {
        accept(Token::COLONEQ);
      }
      values->addValue(this->exprParser->getExpr());

      if (lexer->token()->name->c_str() == Token::COMMA.name->c_str())
      {
        lexer->nextToken();
        continue;
      }

      break;
    }
  }
  else if (lexer->token()->name->c_str() == (Token::SELECT.name->c_str()))
  {
    SQLSelect_ptr select = this->exprParser->createSelectParser()->select();
    if (commentHints != nullptr && !commentHints->empty())
    {
      select->setHeadHint((*commentHints->begin()));
    }
    select->setParent(stmt);
    stmt->setQuery(select);
  }
  else if (lexer->token()->name->c_str() == (Token::LPAREN.name->c_str()))
  {
    lexer->nextToken();
    SQLSelect_ptr select = this->exprParser->createSelectParser()->select();
    select->setParent(stmt);
    stmt->setQuery(select);
    accept(Token::RPAREN);
  }
  else if (lexer->token()->name->c_str() == Token::WITH.name->c_str())
  {
    SQLSelect_ptr query = this->exprParser->createSelectParser()->select();
    stmt->setQuery(query);
  }

  LOG_INFO << "lexer->token->name:" << lexer->token()->getName()->c_str();
  LOG_INFO << "lexer->stringVal_:" << encode_util::UnicodeToUTF8(lexer->stringVal_);
  if (lexer->token()->name->c_str() == Token::ON.name->c_str())
  {
    lexer->nextToken();
    acceptIdentifier("DUPLICATE");
    accept(Token::KEY);
    accept(Token::UPDATE);

    SQLExpr_list_ptr duplicateKeyUpdate = stmt->getDuplicateKeyUpdate();
    for (;;)
    {
      SQLName_ptr name = this->exprParser->name();
      accept(Token::EQ);
      SQLExpr_ptr value;
      try
      {
        value = this->exprParser->getExpr();
      }
      catch (const std::exception &e)
      {
        std::string tmp = "EOF, ";
        tmp += name->getSimpleName()->c_str();
        tmp += "=";
        tmp += e.what();
        throw new ParserException(make_string_ptr(tmp));
      }

      SQLBinaryOpExpr_ptr assignment = SQLBinaryOpExpr_ptr(new SQLBinaryOpExpr(name, SQLBinaryOperator_ptr(new SQLBinaryOperator(&SQLBinaryOperator::Equality)), value));
      assignment->setParent(stmt);
      duplicateKeyUpdate->push_back(assignment);

      if (lexer->token()->name->c_str() == Token::COMMA.name->c_str())
      {
        lexer->nextTokenIdent();
        continue;
      }
      break;
    }
  }

  return stmt;
}

MySqlSelectParser_ptr MySqlStatementParser::createSQLSelectParser()
{
  LOG_INFO << "in createSQLSelectParser";
  return MySqlSelectParser_ptr(new MySqlSelectParser(this->exprParser, selectListCache));
}

SQLStatement_ptr MySqlStatementParser::parseSet()
{
  accept(Token::SET);

  if (lexer->identifierEquals(FnvHash::Constants::PASSWORD))
  {
    lexer->nextToken();
    // SQLSetStatement* stmt = new SQLSetStatement();
    // stmt->setDbType(dbType);
    // stmt->setOption(SQLSetStatement.Option.PASSWORD);

    SQLExpr_ptr user = nullptr;
    if (lexer->token()->name->c_str() == Token::FOR.name->c_str())
    {
      lexer->nextToken();
      user = this->exprParser->name();
    }

    accept(Token::EQ);

    SQLExpr_ptr password = this->exprParser->getExpr();

    // stmt->set(user, password);

    // return stmt;
  }

  BOOL_ptr global = BOOL::FALSE;
  BOOL_ptr session = BOOL::FALSE;
  BOOL_ptr local = BOOL::FALSE;
  if (lexer->identifierEquals(GLOBAL))
  {
    global = BOOL::TRUE;
    lexer->nextToken();
  }
  else if (lexer->identifierEquals(FnvHash::Constants::SESSION))
  {
    session = BOOL::TRUE;
    lexer->nextToken();
  }
  else if (lexer->identifierEquals(FnvHash::Constants::LOCAL))
  {
    lexer->nextToken();
    local = BOOL::TRUE;
  }

  if (lexer->identifierEquals(FnvHash::Constants::TRANSACTION))
  {
    // MySqlSetTransactionStatement* stmt = new MySqlSetTransactionStatement();
    // stmt->setGlobal(global);
    // stmt->setSession(session);

    if (local)
    {
      // stmt->setLocal(BOOL::TRUE);
    }

    lexer->nextToken();
    if (lexer->identifierEquals(make_string_ptr("ISOLATION")))
    {
      lexer->nextToken();
      acceptIdentifier("LEVEL");

      if (lexer->identifierEquals(READ))
      {
        lexer->nextToken();

        if (lexer->identifierEquals(make_string_ptr("UNCOMMITTED")))
        {
          // stmt->setIsolationLevel("READ UNCOMMITTED");
          lexer->nextToken();
        }
        else if (lexer->identifierEquals(WRITE))
        {
          // stmt->setIsolationLevel("READ WRITE");
          lexer->nextToken();
        }
        else if (lexer->identifierEquals(make_string_ptr("ONLY")))
        {
          // stmt->setIsolationLevel("READ ONLY");
          lexer->nextToken();
        }
        else if (lexer->identifierEquals(make_string_ptr("COMMITTED")))
        {
          // stmt->setIsolationLevel("READ COMMITTED");
          lexer->nextToken();
        }
        else
        {
          throw new ParserException(make_string_ptr("UNKOWN TRANSACTION LEVEL : " + encode_util::UnicodeToUTF8(*lexer->stringVal()) + ", " + encode_util::UnicodeToUTF8(lexer->info())));
        }
      }
      else if (lexer->identifierEquals(make_string_ptr("SERIALIZABLE")))
      {
        // stmt->setIsolationLevel("SERIALIZABLE");
        lexer->nextToken();
      }
      else if (lexer->identifierEquals(make_string_ptr("REPEATABLE")))
      {
        lexer->nextToken();
        if (lexer->identifierEquals(READ))
        {
          // stmt->setIsolationLevel("REPEATABLE READ");
          lexer->nextToken();
        }
        else
        {
          throw new ParserException(make_string_ptr("UNKOWN TRANSACTION LEVEL : " + encode_util::UnicodeToUTF8(*lexer->stringVal()) + ", " + encode_util::UnicodeToUTF8(lexer->info())));
        }
      }
      else
      {
        throw new ParserException(make_string_ptr("UNKOWN TRANSACTION LEVEL : " + encode_util::UnicodeToUTF8(*lexer->stringVal()) + ", " + encode_util::UnicodeToUTF8(lexer->info())));
      }
    }
    else if (lexer->identifierEquals(FnvHash::Constants::POLICY))
    {
      lexer->nextToken();
      SQLExpr_ptr policy = this->exprParser->primary();
      // stmt->setPolicy(policy);
    }
    else if (lexer->identifierEquals(READ))
    {
      lexer->nextToken();
      if (lexer->identifierEquals(make_string_ptr("ONLY")))
      {
        // stmt->setAccessModel("ONLY");
        lexer->nextToken();
      }
      else if (lexer->identifierEquals(make_string_ptr("WRITE")))
      {
        // stmt->setAccessModel("WRITE");
        lexer->nextToken();
      }
      else
      {
        throw new ParserException(make_string_ptr("UNKOWN ACCESS MODEL : " + encode_util::UnicodeToUTF8(*lexer->stringVal()) + ", " + encode_util::UnicodeToUTF8(lexer->info())));
      }
    }

    // return stmt;
  }
  else
  {
    // SQLSetStatement* stmt = new SQLSetStatement(getDbType());

    // parseAssignItems(stmt->getItems(), stmt, BOOL::TRUE);

    if (global != BOOL::FALSE)
    {
      // SQLVariantRefExpr* varRef = (SQLVariantRefExpr) stmt->getItems().get(0).getTarget();
      // varRef.setGlobal(BOOL::TRUE);
    }

    if (session != BOOL::FALSE)
    {
      // SQLVariantRefExpr varRef = (SQLVariantRefExpr) stmt->getItems().get(0).getTarget();
      // varRef.setSession(BOOL::TRUE);
    }

    if (lexer->token()->name->c_str() == Token::HINT.name->c_str())
    {
      // stmt->setHints(this->exprParser->parseHints());
    }

    // return stmt;
  }
}

SQLStatement_ptr MySqlStatementParser::parseAlter()
{
  wstring_list_ptr comments = std::make_shared<std::list<wstring_ptr>>();
  if (lexer->isKeepComments() && lexer->hasComment())
  {
    comments = lexer->readAndResetComments();
  }

  Lexer_SavePoint_ptr mark = lexer->mark();
  accept(Token::ALTER);

  if (lexer->token()->name->c_str() == Token::USER.name->c_str())
  {
    // return parseAlterUser();
  }

  BOOL_ptr online = BOOL::FALSE, offline = BOOL::FALSE;

  if (lexer->identifierEquals(make_string_ptr("ONLINE")))
  {
    online = BOOL::TRUE;
    lexer->nextToken();
  }

  if (lexer->identifierEquals(make_string_ptr("OFFLINE")))
  {
    offline = BOOL::TRUE;
    lexer->nextToken();
  }

  BOOL_ptr ignore = BOOL::FALSE;

  if (lexer->identifierEquals(FnvHash::Constants::IGNORE))
  {
    ignore = BOOL::TRUE;
    lexer->nextToken();
  }

  if (lexer->token()->name->c_str() == Token::TABLE.name->c_str())
  {
    SQLStatement_ptr alterTable = parseAlterTable(ignore, online, offline);
    if (!comments->empty())
    {
      alterTable->addBeforeComment(comments);
    }

    return alterTable;
  }

  if (lexer->token()->name->c_str() == Token::DATABASE.name->c_str() ||
      lexer->token()->name->c_str() == Token::SCHEMA.name->c_str())
  {
    return parseAlterDatabase();
  }

  if (lexer->identifierEquals(FnvHash::Constants::EVENT))
  {
    return parseAlterEvent();
  }

  if (lexer->token()->name->c_str() == Token::FUNCTION.name->c_str())
  {
    return parseAlterFunction();
  }

  if (lexer->token()->name->c_str() == Token::PROCEDURE.name->c_str())
  {
    return parseAlterProcedure();
  }

  if (lexer->token()->name->c_str() == Token::TABLESPACE.name->c_str())
  {
    return parseAlterTableSpace();
  }

  if (lexer->token()->name->c_str() == Token::VIEW.name->c_str())
  {
    return parseAlterView();
  }

  if (lexer->token()->name->c_str() == Token::SEQUENCE.name->c_str())
  {
    lexer->reset(mark);
    // return parseAlterSequence();
  }

  if (lexer->identifierEquals(FnvHash::Constants::LOGFILE))
  {
    return parseAlterLogFileGroup();
  }

  if (lexer->identifierEquals(FnvHash::Constants::SERVER))
  {
    return parseAlterServer();
  }

  if (lexer->identifierEquals(FnvHash::Constants::ALGORITHM))
  {
    return parseAlterView();
  }

  if (lexer->identifierEquals(FnvHash::Constants::OUTLINE))
  {
    lexer->reset(mark);
    return parseAlterOutline();
  }

  if (lexer->token()->name->c_str() == Token::FULLTEXT.name->c_str())
  {
    lexer->reset(mark);
    return parseAlterFullTextCharFilter();
  }

  if (lexer->token()->name->c_str() == Token::INDEX.name->c_str())
  {
    lexer->reset(mark);
    accept(Token::ALTER);
    accept(Token::INDEX);

    // SQLAlterIndexStatement* stmt = new SQLAlterIndexStatement();
    // stmt->setName(this->exprParser->name());
    accept(Token::SET);

    accept(Token::FULLTEXT);
  }

  if (lexer->identifierEquals(FnvHash::Constants::DEFINER))
  {
    Lexer_SavePoint_ptr savePoint = lexer->mark();
    lexer->nextToken();
    accept(Token::EQ);
    // this->getExprParser().userName();
    if (lexer->identifierEquals(FnvHash::Constants::EVENT))
    {
      lexer->reset(savePoint);
      return parseAlterEvent();
    }
    else
    {
      lexer->reset(savePoint);
      return parseAlterView();
    }
  }
  if (lexer->identifierEquals(make_string_ptr("TABLEGROUP")))
  {
    lexer->reset(mark);
    return parseAlterTableGroup();
  }

  if (lexer->identifierEquals(make_string_ptr("SYSTEM")))
  {
    lexer->reset(mark);
    return parseAlterSystem();
  }

  if (lexer->identifierEquals(FnvHash::Constants::RESOURCE))
  {
    lexer->reset(mark);
    // return parseAlterResourceGroup();
  }
  if (lexer->identifierEquals(FnvHash::Constants::MATERIALIZED))
  {
    lexer->reset(mark);
    // return parseAlterMaterialized();
  }

  throw new ParserException(make_string_ptr("TODO " + encode_util::UnicodeToUTF8(lexer->info())));
}

SQLStatement_ptr MySqlStatementParser::parseAddManageInstanceGroup()
{
  lexer->nextToken();
  // MySqlManageInstanceGroupStatement* stmt = new MySqlManageInstanceGroupStatement();
  // stmt->setOperation(new SQLIdentifierExpr("ADD"));

  acceptIdentifier("INSTANCE_GROUP");
  for (;;)
  {
    // stmt->getGroupNames().add(exprParser->getExpr());
    if (lexer->token()->name->c_str() == Token::COMMA.name->c_str())
    {
      lexer->nextToken();
      continue;
    }
    break;
  }

  acceptIdentifier("REPLICATION");
  accept(Token::EQ);
  // stmt->setReplication(exprParser->integerExpr());
  // return stmt;
}

SQLStatement_ptr MySqlStatementParser::parseAlterFullTextCharFilter()
{
  accept(Token::ALTER);
  accept(Token::FULLTEXT);

  // MysqlAlterFullTextStatement* stmt = new MysqlAlterFullTextStatement();

  // stmt->setType(parseFullTextType());

  SQLName_ptr name = this->exprParser->name();
  // stmt->setName(name);

  accept(Token::SET);

  SQLAssignItem_ptr item = this->exprParser->parseAssignItem();
  // stmt->setItem(item);
  // return stmt;
}

SQLStatement_ptr MySqlStatementParser::parseAlterTableGroup()
{
  accept(Token::ALTER);
  acceptIdentifier("TABLEGROUP");

  SQLName_ptr name = this->exprParser->name();

  // SQLAlterTableGroupStatement* stmt = new SQLAlterTableGroupStatement();
  // stmt->setName(name);

  for (;;)
  {
    SQLName_ptr key = this->exprParser->name();
    accept(Token::EQ);
    SQLExpr_ptr value = this->exprParser->getExpr();
    // stmt->getOptions().add(new SQLAssignItem(key, value));

    if (lexer->token()->name->c_str() == Token::XEOF.name->c_str())
    {
      break;
    }
  }

  // return stmt;
}

SQLStatement_ptr MySqlStatementParser::parseAlterSystem()
{
  accept(Token::ALTER);
  acceptIdentifier("SYSTEM");

  if (lexer->token()->name->c_str() == Token::SET.name->c_str())
  {
    accept(Token::SET);
    acceptIdentifier("CONFIG");

    // SQLAlterSystemSetConfigStatement* stmt = new SQLAlterSystemSetConfigStatement();

    for (;;)
    {
      SQLName_ptr key = this->exprParser->name();
      accept(Token::EQ);
      SQLExpr_ptr value = this->exprParser->getExpr();
      // stmt->getOptions().add(new SQLAssignItem(key, value));

      if (lexer->token()->name->c_str() == Token::XEOF.name->c_str())
      {
        break;
      }
    }

    // return stmt;
  }
  else if (lexer->identifierEquals(make_string_ptr("GET")))
  {
    acceptIdentifier("GET");
    acceptIdentifier("CONFIG");
    SQLName_ptr name = this->exprParser->name();

    // SQLAlterSystemGetConfigStatement* stmt = new SQLAlterSystemGetConfigStatement();
    // stmt->setName(name);

    // return stmt;
  }

  throw new ParserException(make_string_ptr("TODO " + encode_util::UnicodeToUTF8(lexer->info())));
}

SQLStatement_ptr MySqlStatementParser::parseAlterOutline()
{
  accept(Token::ALTER);

  if (lexer->identifierEquals(FnvHash::Constants::OUTLINE))
  {
    lexer->nextToken();
  }
  else
  {
    throw new ParserException(make_string_ptr("TODO " + encode_util::UnicodeToUTF8(lexer->info())));
  }

  // SQLAlterOutlineStatement* stmt = new SQLAlterOutlineStatement();
  // stmt->setDbType(dbType);

  // stmt->setName(this->exprParser->name());

  if (lexer->identifierEquals(make_string_ptr("RESYNC")))
  {
    lexer->nextToken();
    // stmt->setResync(BOOL::TRUE);
  }

  // return stmt;
}

SQLStatement_ptr MySqlStatementParser::parseAlterView()
{
  if (lexer->token()->name->c_str() == Token::ALTER.name->c_str())
  {
    lexer->nextToken();
  }

  // SQLAlterViewStatement* createView = new SQLAlterViewStatement(getDbType());

  if (lexer->identifierEquals(make_string_ptr("ALGORITHM")))
  {
    lexer->nextToken();
    accept(Token::EQ);
    string_ptr algorithm = make_string_ptr(encode_util::UnicodeToUTF8(*lexer->stringVal()));
    // createView.setAlgorithm(algorithm);
    lexer->nextToken();
  }

  if (lexer->identifierEquals(make_string_ptr("DEFINER")))
  {
    lexer->nextToken();
    accept(Token::EQ);
    SQLName_ptr definer = std::dynamic_pointer_cast<SQLName>(this->exprParser->getExpr());
    // createView.setDefiner(definer);
  }

  if (lexer->identifierEquals(make_string_ptr("SQL")))
  {
    lexer->nextToken();
    acceptIdentifier("SECURITY");
    string_ptr sqlSecurity = make_string_ptr(encode_util::UnicodeToUTF8(*lexer->stringVal()));
    // createView.setSqlSecurity(sqlSecurity);
    lexer->nextToken();
  }

  if (lexer->identifierEquals(FnvHash::Constants::FORCE))
  {
    lexer->nextToken();
    // createView.setForce(BOOL::TRUE);
  }

  this->accept(Token::VIEW);

  if (lexer->token()->name->c_str() == Token::IF.name->c_str() ||
      lexer->identifierEquals(make_string_ptr("IF")))
  {
    lexer->nextToken();
    accept(Token::NOT);
    accept(Token::EXISTS);
    // createView.setIfNotExists(BOOL::TRUE);
  }

  // createView.setName(exprParser->name());

  if (lexer->token()->name->c_str() == Token::LPAREN.name->c_str())
  {
    lexer->nextToken();

    for (;;)
    {
      if (lexer->token()->name->c_str() == Token::CONSTRAINT.name->c_str())
      {
        // SQLTableConstraint* constraint = (SQLTableConstraint) this->exprParser->parseConstaint();
        // createView.addColumn(constraint);
      }
      else
      {
        SQLColumnDefinition_ptr column = SQLColumnDefinition_ptr(new SQLColumnDefinition());
        column->setDbType(dbType);
        SQLName_ptr expr = this->exprParser->name();
        column->setName(expr);

        this->exprParser->parseColumnRest(column);

        if (lexer->token()->name->c_str() == Token::COMMENT.name->c_str())
        {
          lexer->nextToken();

          SQLExpr_ptr comment;
          if (lexer->token()->name->c_str() == Token::LITERAL_ALIAS.name->c_str())
          {
            string_ptr alias = make_string_ptr(encode_util::UnicodeToUTF8(*lexer->stringVal()));
            if (alias->length() > 2 && alias->at(0) == '"' &&
                alias->at(alias->length() - 1) == '"')
            {
              alias = make_string_ptr(alias->substr(1, alias->length() - 1));
            }
            comment = SQLCharExpr_ptr(new SQLCharExpr(alias));
            lexer->nextToken();
          }
          else
          {
            comment = this->exprParser->primary();
          }
          column->setComment(comment);
        }

        // column->setParent(createView);
        // createView.addColumn(column);
      }

      if (lexer->token()->name->c_str() == Token::COMMA.name->c_str())
      {
        lexer->nextToken();
      }
      else
      {
        break;
      }
    }

    accept(Token::RPAREN);
  }

  if (lexer->token()->name->c_str() == Token::COMMENT.name->c_str())
  {
    lexer->nextToken();
    SQLCharExpr_ptr comment = std::dynamic_pointer_cast<SQLCharExpr>(exprParser->primary());
    // createView.setComment(comment);
  }

  this->accept(Token::AS);

  SQLSelectParser_ptr selectParser = this->createSQLSelectParser();
  // createView.setSubQuery(selectParser.select());

  if (lexer->token()->name->c_str() == Token::WITH.name->c_str())
  {
    lexer->nextToken();

    if (lexer->identifierEquals(make_string_ptr("CASCADED")))
    {
      // createView.setWithCascaded(BOOL::TRUE);
      lexer->nextToken();
    }
    else if (lexer->identifierEquals(make_string_ptr("LOCAL")))
    {
      // createView.setWithLocal(BOOL::TRUE);
      lexer->nextToken();
    }
    else if (lexer->identifierEquals(make_string_ptr("READ")))
    {
      lexer->nextToken();
      accept(Token::ONLY);
      // createView.setWithReadOnly(BOOL::TRUE);
    }

    if (lexer->token()->name->c_str() == Token::CHECK.name->c_str())
    {
      lexer->nextToken();
      acceptIdentifier("OPTION");
      // createView.setWithCheckOption(BOOL::TRUE);
    }
  }

  // return createView;
}

SQLStatement_ptr MySqlStatementParser::parseAlterTableSpace()
{
  if (lexer->token()->name->c_str() == Token::ALTER.name->c_str())
  {
    lexer->nextToken();
  }

  accept(Token::TABLESPACE);

  SQLName_ptr name = this->exprParser->name();

  // MySqlAlterTablespaceStatement* stmt = new MySqlAlterTablespaceStatement();
  // stmt->setName(name);

  if (lexer->identifierEquals(FnvHash::Constants::ADD))
  {
    lexer->nextToken();
    acceptIdentifier("DATAFILE");
    SQLExpr_ptr file = this->exprParser->primary();
    // stmt->setAddDataFile(file);
  }
  else if (lexer->token()->name->c_str() == Token::DROP.name->c_str())
  {
    lexer->nextToken();
    acceptIdentifier("DATAFILE");
    SQLExpr_ptr file = this->exprParser->primary();
    // stmt->setDropDataFile(file);
  }

  if (lexer->identifierEquals(FnvHash::Constants::INITIAL_SIZE))
  {
    lexer->nextToken();
    if (lexer->token()->name->c_str() == Token::EQ.name->c_str())
    {
      lexer->nextToken();
    }
    SQLExpr_ptr initialSize = this->exprParser->getExpr();
    // stmt->setInitialSize(initialSize);
  }

  if (lexer->identifierEquals(FnvHash::Constants::WAIT))
  {
    lexer->nextToken();
    // stmt->setWait(BOOL::TRUE);
  }

  if (lexer->identifierEquals(FnvHash::Constants::ENGINE))
  {
    lexer->nextToken();
    if (lexer->token()->name->c_str() == Token::EQ.name->c_str())
    {
      lexer->nextToken();
    }
    SQLExpr_ptr engine = this->exprParser->getExpr();
    // stmt->setEngine(engine);
  }

  // return stmt;
}

SQLStatement_ptr MySqlStatementParser::parseAlterServer()
{
  if (lexer->token()->name->c_str() == Token::ALTER.name->c_str())
  {
    lexer->nextToken();
  }
  acceptIdentifier("SERVER");

  SQLName_ptr name = this->exprParser->name();

  // MySqlAlterServerStatement* stmt = new MySqlAlterServerStatement();
  // stmt->setName(name);

  acceptIdentifier("OPTIONS");
  accept(Token::LPAREN);
  if (lexer->token()->name->c_str() == Token::USER.name->c_str())
  {
    lexer->nextToken();
    SQLExpr_ptr user = this->exprParser->name();
    // stmt->setUser(user);
  }
  accept(Token::RPAREN);

  // return stmt;
}

SQLStatement_ptr MySqlStatementParser::parseCreateLogFileGroup()
{
  if (lexer->token()->name->c_str() == Token::ALTER.name->c_str())
  {
    lexer->nextToken();
  }
  acceptIdentifier("LOGFILE");
  accept(Token::GROUP);

  SQLName_ptr name = this->exprParser->name();

  // MySqlCreateAddLogFileGroupStatement* stmt = new MySqlCreateAddLogFileGroupStatement();
  // stmt->setName(name);

  acceptIdentifier("ADD");
  acceptIdentifier("UNDOFILE");

  SQLExpr_ptr fileName = this->exprParser->primary();
  // stmt->setAddUndoFile(fileName);

  if (lexer->identifierEquals(FnvHash::Constants::INITIAL_SIZE))
  {
    lexer->nextToken();
    if (lexer->token()->name->c_str() == Token::EQ.name->c_str())
    {
      lexer->nextToken();
    }
    SQLExpr_ptr initialSize = this->exprParser->getExpr();
    // stmt->setInitialSize(initialSize);
  }

  if (lexer->identifierEquals(FnvHash::Constants::WAIT))
  {
    lexer->nextToken();
    // stmt->setWait(BOOL::TRUE);
  }

  if (lexer->identifierEquals(FnvHash::Constants::ENGINE))
  {
    lexer->nextToken();
    if (lexer->token()->name->c_str() == Token::EQ.name->c_str())
    {
      lexer->nextToken();
    }
    SQLExpr_ptr engine = this->exprParser->getExpr();
    // stmt->setEngine(engine);
  }

  // return stmt;
}

SQLStatement_ptr MySqlStatementParser::parseAlterLogFileGroup()
{
  if (lexer->token()->name->c_str() == Token::ALTER.name->c_str())
  {
    lexer->nextToken();
  }
  acceptIdentifier("LOGFILE");
  accept(Token::GROUP);

  SQLName_ptr name = this->exprParser->name();

  // MySqlAlterLogFileGroupStatement* stmt = new MySqlAlterLogFileGroupStatement();
  // stmt->setName(name);

  acceptIdentifier("ADD");
  acceptIdentifier("UNDOFILE");

  SQLExpr_ptr fileName = this->exprParser->primary();
  // stmt->setAddUndoFile(fileName);

  if (lexer->identifierEquals(FnvHash::Constants::INITIAL_SIZE))
  {
    lexer->nextToken();
    if (lexer->token()->name->c_str() == Token::EQ.name->c_str())
    {
      lexer->nextToken();
    }
    SQLExpr_ptr initialSize = this->exprParser->getExpr();
    // stmt->setInitialSize(initialSize);
  }

  if (lexer->identifierEquals(FnvHash::Constants::WAIT))
  {
    lexer->nextToken();
    // stmt->setWait(BOOL::TRUE);
  }

  if (lexer->identifierEquals(FnvHash::Constants::ENGINE))
  {
    lexer->nextToken();
    if (lexer->token()->name->c_str() == Token::EQ.name->c_str())
    {
      lexer->nextToken();
    }
    SQLExpr_ptr engine = this->exprParser->getExpr();
    // stmt->setEngine(engine);
  }

  // return stmt;
}

SQLStatement_ptr MySqlStatementParser::parseAlterProcedure()
{
  if (lexer->token()->name->c_str() == Token::ALTER.name->c_str())
  {
    lexer->nextToken();
  }
  accept(Token::PROCEDURE);

  // SQLAlterProcedureStatement stmt = new SQLAlterProcedureStatement();
  // stmt->setDbType(dbType);

  SQLName_ptr name = this->exprParser->name();
  // stmt->setName(name);

  // for mysql
  for (;;)
  {
    if (lexer->token()->name->c_str() == Token::COMMENT.name->c_str())
    {
      lexer->nextToken();
      SQLExpr_ptr comment = this->exprParser->primary();
      // stmt->setComment(comment);
    }
    else if (lexer->identifierEquals(FnvHash::Constants::LANGUAGE))
    {
      lexer->nextToken();
      acceptIdentifier("SQL");
      // stmt->setLanguageSql(BOOL::TRUE);
    }
    else if (lexer->identifierEquals(FnvHash::Constants::SQL))
    {
      lexer->nextToken();
      acceptIdentifier("SECURITY");

      SQLExpr_ptr sqlSecurity = this->exprParser->name();
      // stmt->setSqlSecurity(sqlSecurity);
    }
    else if (lexer->identifierEquals(FnvHash::Constants::CONTAINS) ||
             lexer->token()->name->c_str() == Token::CONTAINS.name->c_str())
    {
      lexer->nextToken();
      acceptIdentifier("SQL");
      // stmt->setContainsSql(BOOL::TRUE);
    }
    else
    {
      break;
    }
  }

  // return stmt;
}

SQLStatement_ptr MySqlStatementParser::parseAlterFunction()
{
  if (lexer->token()->name->c_str() == Token::ALTER.name->c_str())
  {
    lexer->nextToken();
  }
  accept(Token::FUNCTION);

  // SQLAlterFunctionStatement* stmt = new SQLAlterFunctionStatement();
  // stmt->setDbType(dbType);

  SQLName_ptr name = this->exprParser->name();
  // stmt->setName(name);

  // for mysql
  for (;;)
  {
    if (lexer->token()->name->c_str() == Token::COMMENT.name->c_str())
    {
      lexer->nextToken();
      SQLExpr_ptr comment = this->exprParser->primary();
      // stmt->setComment(comment);
    }
    else if (lexer->identifierEquals(FnvHash::Constants::LANGUAGE))
    {
      lexer->nextToken();
      acceptIdentifier("SQL");
      // stmt->setLanguageSql(BOOL::TRUE);
    }
    else if (lexer->identifierEquals(FnvHash::Constants::SQL))
    {
      lexer->nextToken();
      acceptIdentifier("SECURITY");

      SQLExpr_ptr sqlSecurity = this->exprParser->name();
      // stmt->setSqlSecurity(sqlSecurity);
    }
    else if (lexer->identifierEquals(FnvHash::Constants::CONTAINS) ||
             lexer->token()->name->c_str() == Token::CONTAINS.name->c_str())
    {
      lexer->nextToken();
      acceptIdentifier("SQL");
      // stmt->setContainsSql(BOOL::TRUE);
    }
    else
    {
      break;
    }
  }

  // return stmt;
}

SQLStatement_ptr MySqlStatementParser::parseCreateEvent()
{
  if (lexer->token()->name->c_str() == Token::CREATE.name->c_str())
  {
    lexer->nextToken();
  }

  // MySqlCreateEventStatement* stmt = new MySqlCreateEventStatement();

  if (lexer->identifierEquals(FnvHash::Constants::DEFINER))
  {
    lexer->nextToken();
    accept(Token::EQ);
    // SQLName_ptr  definer = this->getExprParser().userName();
    // stmt->setDefiner(definer);

    if (lexer->token()->name->c_str() == Token::LPAREN.name->c_str())
    {
      lexer->nextToken();
      accept(Token::RPAREN);
    }
  }

  acceptIdentifier("EVENT");

  if (lexer->token()->name->c_str() == Token::IF.name->c_str())
  {
    lexer->nextToken();
    accept(Token::NOT);
    accept(Token::EXISTS);
    // stmt->setIfNotExists(BOOL::TRUE);
  }

  SQLName_ptr eventName = this->exprParser->name();
  // stmt->setName(eventName);

  while (lexer->token()->name->c_str() == Token::ON.name->c_str())
  {
    lexer->nextToken();
    if (lexer->identifierEquals(FnvHash::Constants::SCHEDULE))
    {
      lexer->nextToken();
      // MySqlEventSchedule* schedule = parseSchedule();
      // stmt->setSchedule(schedule);
    }
    else if (lexer->identifierEquals(FnvHash::Constants::COMPLETION))
    {
      lexer->nextToken();

      BOOL_ptr value;
      if (lexer->token()->name->c_str() == Token::NOT.name->c_str())
      {
        lexer->nextToken();
        value = BOOL::FALSE;
      }
      else
      {
        value = BOOL::TRUE;
      }
      acceptIdentifier("PRESERVE");
      // stmt->setOnCompletionPreserve(value);
    }
    else
    {
      throw new ParserException(make_string_ptr("TODO " + encode_util::UnicodeToUTF8(lexer->info())));
    }
  }

  if (lexer->identifierEquals(FnvHash::Constants::RENAME))
  {
    lexer->nextToken();
    accept(Token::TO);
    SQLName_ptr renameTo = this->exprParser->name();
    // stmt->setRenameTo(renameTo);
  }

  if (lexer->token()->name->c_str() == Token::ENABLE.name->c_str())
  {
    // stmt->setEnable(BOOL::TRUE);
    lexer->nextToken();
  }
  else if (lexer->token()->name->c_str() == Token::DISABLE.name->c_str())
  {
    lexer->nextToken();
    // stmt->setEnable(BOOL::FALSE);

    if (lexer->token()->name->c_str() == Token::ON.name->c_str())
    {
      lexer->nextToken();
      acceptIdentifier("SLAVE");
      // stmt->setDisableOnSlave(BOOL::TRUE);
    }
  }

  if (lexer->token()->name->c_str() == Token::COMMENT.name->c_str())
  {
    lexer->nextToken();
    SQLExpr_ptr comment = this->exprParser->primary();
    // stmt->setComment(comment);
  }

  if (lexer->token()->name->c_str() == Token::DO.name->c_str())
  {
    lexer->nextToken();
    SQLStatement_ptr eventBody = this->parseStatement();
    // stmt->setEventBody(eventBody);
  }
  else if (lexer->token()->name->c_str() == Token::IDENTIFIER.name->c_str())
  {
    SQLExpr_ptr expr = this->exprParser->getExpr();
    // SQLExprStatement eventBody = new SQLExprStatement(expr);
    // eventBody.setDbType(dbType);
    // stmt->setEventBody(eventBody);
  }

  // return stmt;
}

SQLStatement_ptr MySqlStatementParser::parseAlterEvent()
{
  if (lexer->token()->name->c_str() == Token::ALTER.name->c_str())
  {
    lexer->nextToken();
  }

  // MySqlAlterEventStatement* stmt = new MySqlAlterEventStatement();

  if (lexer->identifierEquals(FnvHash::Constants::DEFINER))
  {
    lexer->nextToken();
    accept(Token::EQ);
    // SQLName_ptr  definer = this->getExprParser().userName();
    // stmt->setDefiner(definer);
  }

  acceptIdentifier("EVENT");

  SQLName_ptr eventName = this->exprParser->name();
  // stmt->setName(eventName);

  while (lexer->token()->name->c_str() == Token::ON.name->c_str())
  {
    lexer->nextToken();
    if (lexer->identifierEquals(FnvHash::Constants::SCHEDULE))
    {
      lexer->nextToken();
      // MySqlEventSchedule* schedule = parseSchedule();
      // stmt->setSchedule(schedule);
    }
    else if (lexer->identifierEquals(FnvHash::Constants::COMPLETION))
    {
      lexer->nextToken();

      BOOL_ptr value;
      if (lexer->token()->name->c_str() == Token::NOT.name->c_str())
      {
        lexer->nextToken();
        value = BOOL::FALSE;
      }
      else
      {
        value = BOOL::TRUE;
      }
      acceptIdentifier("PRESERVE");
      // stmt->setOnCompletionPreserve(value);
    }
    else
    {
      throw new ParserException(make_string_ptr("TODO " + encode_util::UnicodeToUTF8(lexer->info())));
    }
  }

  if (lexer->identifierEquals(FnvHash::Constants::RENAME))
  {
    lexer->nextToken();
    accept(Token::TO);
    SQLName_ptr renameTo = this->exprParser->name();
    // stmt->setRenameTo(renameTo);
  }

  if (lexer->token()->name->c_str() == Token::ENABLE.name->c_str())
  {
    // stmt->setEnable(BOOL::TRUE);
    lexer->nextToken();
  }
  else if (lexer->token()->name->c_str() == Token::DISABLE.name->c_str())
  {
    lexer->nextToken();
    // stmt->setEnable(BOOL::FALSE);

    if (lexer->token()->name->c_str() == Token::ON.name->c_str())
    {
      lexer->nextToken();
      acceptIdentifier("SLAVE");
      // stmt->setDisableOnSlave(BOOL::TRUE);
    }
  }

  if (lexer->token()->name->c_str() == Token::COMMENT.name->c_str())
  {
    lexer->nextToken();
    SQLExpr_ptr comment = this->exprParser->primary();
    // stmt->setComment(comment);
  }

  if (lexer->token()->name->c_str() == Token::DO.name->c_str())
  {
    lexer->nextToken();
    SQLStatement_ptr eventBody = this->parseStatement();
    // stmt->setEventBody(eventBody);
  }
  else if (lexer->token()->name->c_str() == Token::IDENTIFIER.name->c_str())
  {
    SQLExpr_ptr expr = this->exprParser->getExpr();
    // SQLExprStatement eventBody = new SQLExprStatement(expr);
    // eventBody.setDbType(dbType);
    // stmt->setEventBody(eventBody);
  }

  // return stmt;
}

// MySqlEventSchedule* MySqlStatementParser::parseSchedule() {
//     MySqlEventSchedule schedule = new MySqlEventSchedule();

//     if (lexer->identifierEquals(FnvHash::Constants::AT)) {
//         lexer->nextToken();
//         schedule.setAt(this->exprParser->getExpr());
//     } else if (lexer->identifierEquals(FnvHash::Constants::EVERY)) {
//         lexer->nextToken();
//         SQLExpr_ptr value = this->exprParser->getExpr();
//         string_ptr  unit = lexer->stringVal();
//         lexer->nextToken();

//         SQLIntervalExpr intervalExpr = new SQLIntervalExpr();
//         intervalExpr.setValue(value);
//         intervalExpr.setUnit(SQLIntervalUnit.valueOf(unit.toUpperCase()));

//         schedule.setEvery(intervalExpr);
//     }

//     if (lexer->identifierEquals(FnvHash::Constants::STARTS)) {
//         lexer->nextToken();
//         schedule.setStarts(this->exprParser->getExpr());

//         if (lexer->identifierEquals(FnvHash::Constants::ENDS)) {
//             lexer->nextToken();
//             schedule.setEnds(this->exprParser->getExpr());
//         }
//     } else if (lexer->identifierEquals(FnvHash::Constants::ENDS)) {
//         lexer->nextToken();
//         schedule.setEnds(this->exprParser->getExpr());
//     }

//     return schedule;
// }

// BOOL_ptr MySqlStatementParser::parseAlterSpecification(SQLAlterTableStatement* stmt) {
//     // Specification except table options.
//     if (lexer->token()->name->c_str() == Token::IDENTIFIER.name->c_str()) {
//             if (lexer->identifierEquals(FnvHash::Constants::ADD)) {
//                 lexer->nextToken();

//                 BOOL_ptr hasConstraint = BOOL::FALSE;
//                 SQLName_ptr  constraintSymbol = nullptr;

//                     // ADD [COLUMN] col_name column_definition [FIRST | AFTER col_name]
//                     // ADD [COLUMN] (col_name column_definition,...)
//                 if (lexer->token()->name->c_str() == Token::COLUMN) {
//                         lexer->nextToken();
//                 } else if (lexer->token()->name->c_str() == Token::LPAREN.name->c_str()) {
//                         parseAlterTableAddColumn(stmt);
//                         return BOOL::TRUE;

//                     // ADD {FULLTEXT|SPATIAL} [INDEX|KEY] [index_name] (key_part,...) [index_option] ...
//                 } else if (lexer->token()->name->c_str() == Token::FULLTEXT ||
//                            lexer->token()->name->c_str() == Token::IDENTIFIER.name->c_str()) {
//                         if (lexer->token()->name->c_str() == Token::FULLTEXT
//                                 || lexer->identifierEquals(FnvHash::Constants::SPATIAL)
//                                 || lexer->identifierEquals(FnvHash::Constants::CLUSTERED)
//                                 || lexer->identifierEquals(FnvHash::Constants::CLUSTERING)
//                                 || lexer->identifierEquals(FnvHash::Constants::ANN)
//                                 || lexer->identifierEquals(FnvHash::Constants::GLOBAL)
//                                 || lexer->identifierEquals(FnvHash::Constants::LOCAL)) {
//                             // Index.
//                             SQLAlterTableAddIndex* item = new SQLAlterTableAddIndex();
//                             this->exprParser->parseIndex(item.getIndexDefinition());
//                             stmt->addItem(item);
//                         } else if (lexer->identifierEquals(FnvHash::Constants::EXTPARTITION)) {
//                             // Caution: Not in MySql documents.
//                             lexer->nextToken();
//                             accept(Token::LPAREN);
//                             SQLAlterTableAddExtPartition* extPartitionItem = new SQLAlterTableAddExtPartition();
//                             MySqlExtPartition* partitionDef = parseExtPartition();
//                             extPartitionItem.setExPartition(partitionDef);
//                             stmt->addItem(extPartitionItem);
//                             accept(Token::RPAREN);
//                         } else {
//                             // Add column.
//                             parseAlterTableAddColumn(stmt);
//                         }
//                         return BOOL::TRUE;

//                     // ADD {INDEX|KEY} [index_name] [index_type] (key_part,...) [index_option] ...
//                 } else if (lexer->token()->name->c_str() == Token::INDEX ||
//                            lexer->token()->name->c_str() == Token::KEY) {
//                         SQLAlterTableAddIndex* item = new SQLAlterTableAddIndex();
//                         this->exprParser->parseIndex(item.getIndexDefinition());
//                         stmt->addItem(item);
//                         return BOOL::TRUE;

//                     // ADD [CONSTRAINT [symbol]] PRIMARY KEY [index_type] (key_part,...) [index_option] ...
//                     // ADD [CONSTRAINT [symbol]] UNIQUE [INDEX|KEY] [index_name] [index_type] (key_part,...) [index_option] ...
//                     // ADD [CONSTRAINT [symbol]] FOREIGN KEY [index_name] (col_name,...) reference_definition
//                 } else if (lexer->token()->name->c_str() == Token::CONSTRAINT.name->c_str()) {
//                         hasConstraint = BOOL::TRUE;
//                         lexer->nextToken();
//                         if (lexer->token()->name->c_str() == Token::IDENTIFIER.name->c_str()) {
//                             constraintSymbol = this->exprParser->name();
//                             if (lexer->token()->name->c_str() != Token::PRIMARY && lexer->token()->name->c_str() != Token::UNIQUE && lexer->token()->name->c_str() != Token::FOREIGN && *lexer->token() != CHECK) {
//                                 throw new ParserException("syntax error, expect PRIMARY, UNIQUE or FOREIGN, actual " + lexer->token()->getName() + ", " + lexer->info());
//                             }
//                         }
//                 } else if (lexer->token()->name->c_str() == Token::PRIMARY ||
//                            lexer->token()->name->c_str() == Token::UNIQUE ||
//                            lexer->token()->name->c_str() == Token::FOREIGN ||
//                            lexer->token()->name->c_str() == Token::CHECK.name->c_str()) {
//                         // Constraint.
//                         if (lexer->token()->name->c_str() == Token::FOREIGN) {
//                             // MysqlForeignKey* fk = this->getExprParser().parseForeignKey();
//                             if (constraintSymbol != nullptr) {
//                                 // fk.setName(constraintSymbol);
//                             }
//                             fk.setHasConstraint(hasConstraint);
//                             SQLAlterTableAddConstraint* constraint = new SQLAlterTableAddConstraint(fk);
//                             stmt->addItem(constraint);
//                         } else if (lexer->token()->name->c_str() == Token::PRIMARY) {
//                             MySqlPrimaryKey pk = new MySqlPrimaryKey();
//                             if (constraintSymbol != nullptr) {
//                                 pk.setName(constraintSymbol);
//                             }
//                             pk.getIndexDefinition().setHasConstraint(hasConstraint);
//                             pk.getIndexDefinition().setSymbol(constraintSymbol);
//                             this->exprParser->parseIndex(pk.getIndexDefinition());
//                             SQLAlterTableAddConstraint* item = new SQLAlterTableAddConstraint(pk);
//                             stmt->addItem(item);
//                         } else if (lexer->token()->name->c_str() == Token::UNIQUE) {
//                             MySqlUnique uk = new MySqlUnique();
//                             uk.getIndexDefinition().setHasConstraint(hasConstraint);
//                             uk.getIndexDefinition().setSymbol(constraintSymbol);
//                             this->exprParser->parseIndex(uk.getIndexDefinition());
//                             SQLAlterTableAddConstraint* item = new SQLAlterTableAddConstraint(uk);
//                             stmt->addItem(item);
//                         } else if (lexer->token()->name->c_str() == Token::CHECK.name->c_str()) { // ADD CHECK (expr)
//                             lexer->nextToken();
//                             accept(Token::LPAREN);
//                             SQLCheck check = new SQLCheck();
//                             if (nullptr != constraintSymbol) {
//                                 check.setName(constraintSymbol);
//                             }
//                             check.setExpr(this->exprParser->getExpr());
//                             accept(Token::RPAREN);
//                             BOOL_ptr enforce = BOOL::TRUE;
//                             if (lexer->token()->name->c_str() == Token::NOT.name->c_str()) {
//                                 enforce = BOOL::FALSE;
//                                 lexer->nextToken();
//                             }
//                             if (StringUtils::iequals(lexer->stringVal(), "ENFORCED")) {
//                                 check.setEnforced(enforce);
//                                 lexer->nextToken();
//                             }
//                             SQLAlterTableAddConstraint* item = new SQLAlterTableAddConstraint(check);
//                             stmt->addItem(item);
//                         }
//                         return BOOL::TRUE;

//                     // ADD PARTITION (partition_definition)
//                 } else if (lexer->token()->name->c_str() == Token::PARTITION.name->c_str()) {
//                         lexer->nextToken();
//                         SQLAlterTableAddPartition* item = new SQLAlterTableAddPartition();
//                         if (lexer->identifierEquals(make_string_ptr("PARTITIONS"))) {
//                             lexer->nextToken();
//                             item.setPartitionCount(this->exprParser->integerExpr());
//                         }
//                         if (lexer->token()->name->c_str() == Token::LPAREN.name->c_str()) {
//                             lexer->nextToken();

//                             for (; ; ) {
//                                 // SQLPartition* partition = this->getExprParser().parsePartition();
//                                 // item.addPartition(partition);
//                                 if (*lexer->token() == COMMA) {
//                                     lexer->nextToken();

//                                     if (*lexer->token() == PARTITION) {
//                                         continue;
//                                     }
//                                 }
//                                 break;
//                             }
//                             accept(Token::RPAREN);
//                         }
//                         stmt->addItem(item);
//                         return BOOL::TRUE;
//                     }

//                 else {
//                         // Add column.
//                         parseAlterTableAddColumn(stmt);
//                         return BOOL::TRUE;
//                 }
//             } else if (lexer->identifierEquals(FnvHash::Constants::ALGORITHM)) {
//                 // ALGORITHM [=] {DEFAULT|INPLACE|COPY}
//                 lexer->nextToken();
//                 if (lexer->token()->name->c_str() == Token::EQ.name->c_str()) {
//                     lexer->nextToken();
//                 }
//                 stmt->addItem(new MySqlAlterTableOption("ALGORITHM", lexer->stringVal()));
//                 lexer->nextToken();
//                 return BOOL::TRUE;
//             } else if (lexer->identifierEquals(FnvHash::Constants::CHANGE)) {
//                 // CHANGE [COLUMN] old_col_name new_col_name column_definition [FIRST|AFTER col_name]
//                 lexer->nextToken();
//                 if (lexer->token()->name->c_str() == Token::COLUMN) {
//                     lexer->nextToken();
//                 }
//                 MySqlAlterTableChangeColumn* item = new MySqlAlterTableChangeColumn();
//                 item.setColumnName(this->exprParser->name());
//                 item.setNewColumnDefinition(this->exprParser->parseColumn());
//                 if (lexer->identifierEquals("AFTER")) {
//                     lexer->nextToken();
//                     item.setAfterColumn(this->exprParser->name());
//                 } else if (lexer->identifierEquals("FIRST")) {
//                     lexer->nextToken();
//                     if (lexer->token()->name->c_str() == Token::IDENTIFIER.name->c_str()) {
//                         item.setFirstColumn(this->exprParser->name());
//                     } else {
//                         item.setFirst(BOOL::TRUE);
//                     }
//                 }
//                 stmt->addItem(item);
//                 return BOOL::TRUE;
//             } else if (lexer->identifierEquals(FnvHash::Constants::CONVERT)) {
//                 // CONVERT TO CHARACTER SET charset_name [COLLATE collation_name]
//                 lexer->nextToken();
//                 accept(Token::TO);
//                 acceptIdentifier("CHARACTER");
//                 accept(Token::SET);
//                 SQLAlterTableConvertCharSet* item = new SQLAlterTableConvertCharSet();
//                 SQLExpr_ptr charset = this->exprParser->name();
//                 item.setCharset(charset);
//                 if (lexer->identifierEquals("COLLATE")) {
//                     lexer->nextToken();
//                     SQLExpr_ptr collate = this->exprParser->primary();
//                     item.setCollate(collate);
//                 }
//                 stmt->addItem(item);
//                 return BOOL::TRUE;
//             } else if (lexer->identifierEquals(FnvHash::Constants::DISCARD)) {
//                 // DISCARD PARTITION {partition_names | ALL} TABLESPACE
//                 // DISCARD TABLESPACE
//                 lexer->nextToken();
//                 if (lexer->token()->name->c_str() == Token::PARTITION.name->c_str()) {
//                     lexer->nextToken();
//                     SQLAlterTableDiscardPartition* item = new SQLAlterTableDiscardPartition();

//                     if (lexer->token()->name->c_str() == Token::ALL) {
//                         lexer->nextToken();
//                         item.getPartitions().add(new SQLIdentifierExpr("ALL"));
//                     } else {
//                         this->exprParser->names(item.getPartitions(), item);
//                     }

//                     if (lexer->token()->name->c_str() == Token::TABLESPACE.name->c_str()) {
//                         lexer->nextToken();
//                         item.setTablespace(BOOL::TRUE);
//                     }

//                     stmt->addItem(item);
//                 } else {
//                     accept(Token::TABLESPACE);
//                     MySqlAlterTableDiscardTablespace* item = new MySqlAlterTableDiscardTablespace();
//                     stmt->addItem(item);
//                 }
//                 return BOOL::TRUE;
//             } else if (lexer->identifierEquals(FnvHash::Constants::IMPORT)) {
//                 // IMPORT PARTITION {partition_names | ALL} TABLESPACE
//                 // IMPORT TABLESPACE
//                 lexer->nextToken();
//                 if (lexer->token()->name->c_str() == Token::PARTITION.name->c_str()) {
//                     lexer->nextToken();
//                     SQLAlterTableImportPartition* item = new SQLAlterTableImportPartition();

//                     if (lexer->token()->name->c_str() == Token::ALL) {
//                         lexer->nextToken();
//                         item.getPartitions().add(new SQLIdentifierExpr("ALL"));
//                     } else {
//                         this->exprParser->names(item.getPartitions(), item);
//                     }

//                     if (lexer->token()->name->c_str() == Token::TABLESPACE.name->c_str()) {
//                         lexer->nextToken();
//                         item.setTablespace(BOOL::TRUE);
//                     }

//                     stmt->addItem(item);
//                 } else {
//                     accept(Token::TABLESPACE);
//                     MySqlAlterTableImportTablespace* item = new MySqlAlterTableImportTablespace();
//                     stmt->addItem(item);
//                 }
//                 return BOOL::TRUE;
//             } else if (lexer->identifierEquals(FnvHash::Constants::FORCE)) {
//                 // FORCE
//                 lexer->nextToken();
//                 MySqlAlterTableForce* item = new MySqlAlterTableForce();
//                 stmt->addItem(item);
//                 return BOOL::TRUE;
//             } else if (lexer->identifierEquals(FnvHash::Constants::MODIFY)) {
//                 // MODIFY [COLUMN] col_name column_definition [FIRST | AFTER col_name]
//                 lexer->nextToken();
//                 if (lexer->token()->name->c_str() == Token::COLUMN) {
//                     lexer->nextToken();
//                 }
//                 BOOL_ptr paren = BOOL::FALSE;
//                 if (lexer->token()->name->c_str() == Token::LPAREN.name->c_str()) {
//                     paren = BOOL::TRUE;
//                     lexer->nextToken();
//                 }
//                 for (; ; ) {
//                     MySqlAlterTableModifyColumn* item = new MySqlAlterTableModifyColumn();
//                     item.setNewColumnDefinition(this->exprParser->parseColumn());
//                     if (lexer->identifierEquals("AFTER")) {
//                         lexer->nextToken();
//                         item.setAfterColumn(this->exprParser->name());
//                     } else if (lexer->identifierEquals("FIRST")) {
//                         lexer->nextToken();
//                         if (lexer->token()->name->c_str() == Token::IDENTIFIER.name->c_str()) {
//                             item.setFirstColumn(this->exprParser->name());
//                         } else {
//                             item.setFirst(BOOL::TRUE);
//                         }
//                     }
//                     stmt->addItem(item);

//                     if (paren && lexer->token() == Token::COMMA.name->c_str()) {
//                         lexer->nextToken();
//                         continue;
//                     }
//                     break;
//                 }

//                 if (paren) {
//                     accept(Token::RPAREN);
//                 }
//                 return BOOL::TRUE;
//             } else if (lexer->identifierEquals(FnvHash::Constants::RENAME)) {
//                 // RENAME {INDEX|KEY} old_index_name TO new_index_name
//                 // RENAME [TO|AS] new_tbl_name
//                 lexer->nextToken();

//                 if (lexer->token()->name->c_str() == Token::INDEX ||
//                     lexer->token()->name->c_str() == Token::EY) {
//                         lexer->nextToken();
//                         SQLName_ptr  name = this->exprParser->name();
//                         accept(Token::TO);
//                         SQLName_ptr  to = this->exprParser->name();
//                         SQLAlterTableRenameIndex* item = new SQLAlterTableRenameIndex(name, to);
//                         stmt->addItem(item);
//                         return BOOL::TRUE;
//                     }

//                 else if (lexer->token()->name->c_str() == Token::COLUMN) {
//                         lexer->nextToken();
//                         SQLName_ptr  columnName = exprParser->name();
//                         accept(Token::TO);
//                         SQLName_ptr  toName = this->exprParser->name();
//                         SQLAlterTableRenameColumn* renameColumn = new SQLAlterTableRenameColumn();
//                         renameColumn.setColumn(columnName);
//                         renameColumn.setTo(toName);
//                         stmt->addItem(renameColumn);
//                         return BOOL::TRUE;
//                     }

//                 else if (lexer->token()->name->c_str() == Token::TO ||
//                          lexer->token()->name->c_str() == Token::AS) {
//                         lexer->nextToken(); }
//                 else if (lexer->token()->name->c_str() == Token::IDENTIFIER.name->c_str()) {
//                         SQLAlterTableRename* item = new SQLAlterTableRename();
//                         SQLName_ptr  to = this->exprParser->name();
//                         item.setTo(to);
//                         stmt->addItem(item);
//                         return BOOL::TRUE;
//                 }
//             } else if (lexer->identifierEquals(FnvHash::Constants::WITHOUT)) {
//                 // WITHOUT VALIDATION
//                 lexer->nextToken();
//                 acceptIdentifier("VALIDATION");
//                 MySqlAlterTableValidation* item = new MySqlAlterTableValidation();
//                 item.setWithValidation(BOOL::FALSE);
//                 stmt->addItem(item);
//                 return BOOL::TRUE;
//             } else if (lexer->identifierEquals("COALESCE")) {
//                 lexer->nextToken();
//                 accept(Token::PARTITION);

//                 SQLAlterTableCoalescePartition* item = new SQLAlterTableCoalescePartition();
//                 SQLIntegerExpr countExpr = this->exprParser->integerExpr();
//                 item.setCount(countExpr);
//                 stmt->addItem(item);
//                 return BOOL::TRUE;
//             } else if (lexer->identifierEquals("REORGANIZE")) {
//                 // REORGANIZE PARTITION partition_names INTO (partition_definitions)
//                 lexer->nextToken();
//                 accept(Token::PARTITION);

//                 SQLAlterTableReOrganizePartition* item = new SQLAlterTableReOrganizePartition();

//                 this->exprParser->names(item.getNames(), item);

//                 accept(Token::INTO);
//                 accept(Token::LPAREN);
//                 for (; ; ) {
//                     // SQLPartition* partition = this->getExprParser().parsePartition();

//                     // item.addPartition(partition);

//                     if (lexer->token()->name->c_str() == Token::COMMA.name->c_str()) {
//                         lexer->nextToken();
//                         continue;
//                     } else {
//                         break;
//                     }
//                 }
//                 accept(Token::RPAREN);
//                 stmt->addItem(item);
//                 return BOOL::TRUE;
//             } else if (lexer->identifierEquals(FnvHash::Constants::EXCHANGE)) {
//                 // EXCHANGE PARTITION partition_name WITH TABLE tbl_name [{WITH|WITHOUT} VALIDATION]
//                 lexer->nextToken();
//                 accept(Token::PARTITION);

//                 SQLAlterTableExchangePartition* item = new SQLAlterTableExchangePartition();

//                 SQLName_ptr  partition = this->exprParser->name();
//                 item.addPartition(partition);

//                 accept(Token::WITH);
//                 accept(Token::TABLE);
//                 SQLName_ptr  table = this->exprParser->name();
//                 item.setTable(table);

//                 if (lexer->token()->name->c_str() == Token::WITH.name->c_str()) {
//                     lexer->nextToken();
//                     acceptIdentifier("VALIDATION");
//                     item.setValidation(BOOL::TRUE);
//                 } else if (lexer->identifierEquals(FnvHash::Constants::WITHOUT)) {
//                     lexer->nextToken();
//                     acceptIdentifier("VALIDATION");
//                     item.setValidation(BOOL::FALSE);
//                 }
//                 stmt->addItem(item);
//                 return BOOL::TRUE;
//             } else if (lexer->identifierEquals("REBUILD")) {
//                 // REBUILD PARTITION {partition_names | ALL}
//                 lexer->nextToken();
//                 accept(Token::PARTITION);

//                 SQLAlterTableRebuildPartition* item = new SQLAlterTableRebuildPartition();

//                 if (lexer->token()->name->c_str() == Token::ALL) {
//                     lexer->nextToken();
//                     item.getPartitions().add(new SQLIdentifierExpr("ALL"));
//                 } else {
//                     this->exprParser->names(item.getPartitions(), item);
//                 }
//                 stmt->addItem(item);
//                 return BOOL::TRUE;
//             } else if (lexer->identifierEquals("REPAIR")) {
//                 // REPAIR PARTITION {partition_names | ALL}
//                 lexer->nextToken();
//                 accept(Token::PARTITION);

//                 SQLAlterTableRepairPartition* item = new SQLAlterTableRepairPartition();

//                 if (lexer->token()->name->c_str() == Token::ALL) {
//                     lexer->nextToken();
//                     item.getPartitions().add(new SQLIdentifierExpr("ALL"));
//                 } else {
//                     this->exprParser->names(item.getPartitions(), item);
//                 }
//                 stmt->addItem(item);
//                 return BOOL::TRUE;
//             } else if (lexer->identifierEquals(FnvHash::Constants::REMOVE)) {
//                 // REMOVE PARTITIONING
//                 lexer->nextToken();
//                 acceptIdentifier("PARTITIONING");
//                 stmt->setRemovePatiting(BOOL::TRUE);
//             } else if (lexer->identifierEquals(make_string_ptr("UPGRADE"))) {
//                 // UPGRADE PARTITIONING
//                 lexer->nextToken();
//                 acceptIdentifier("PARTITIONING");
//                 stmt->setUpgradePatiting(BOOL::TRUE);
//             } else if (lexer->identifierEquals("HOT_PARTITION_COUNT")) {
//                 // UPGRADE PARTITIONING
//                 lexer->nextToken();
//                 accept(EQ);
//                 try {
//                     stmt->getTableOptions().add(new SQLAssignItem(new SQLIdentifierExpr("HOT_PARTITION_COUNT"), this->exprParser->integerExpr()));
//                 } catch (Exception e) {
//                     throw new ParserException("only integer number is supported for hot_partition_count");
//                 }
//             }

//             //
//             // Other not in MySql documents.
//             //

//             else if (lexer->identifierEquals(FnvHash::Constants::PARTITIONS)) {
//                 // Caution: Not in MySql documents.
//                 SQLAlterTablePartitionCount* item = new SQLAlterTablePartitionCount();
//                 lexer->nextToken();
//                 if (lexer->token()->name->c_str() == Token::EQ.name->c_str()) {
//                     lexer->nextToken();
//                 }
//                 item.setCount((SQLIntegerExpr) exprParser->integerExpr());
//                 stmt->addItem(item);
//                 return BOOL::TRUE;
//             } else if (lexer->identifierEquals(FnvHash::Constants::SUBPARTITION)) {
//                 // Caution: Not in MySql documents.
//                 lexer->nextToken();
//                 if (lexer->identifierEquals(FnvHash::Constants::LIFECYCLE)) {
//                     lexer->nextToken();
//                     SQLAlterTableSubpartitionLifecycle* item = new SQLAlterTableSubpartitionLifecycle();
//                     if (lexer->token()->name->c_str() == Token::LITERAL_INT) {
//                         for (; ; ) {
//                             item.getPartitionIds().add(this->exprParser->integerExpr());
//                             string_ptr  pidStr = lexer->stringVal();
//                             accept(Token::VARIANT);
//                             string_ptr  s = pidStr.replaceAll(":", "");
//                             if (StringUtils.isEmpty(s)) {
//                                 item.getSubpartitionLifeCycle().add(exprParser->integerExpr());
//                             } else {
//                                 item.getSubpartitionLifeCycle().add(new SQLIntegerExpr(Integer.valueOf(s)));
//                             }

//                             if (lexer->token()->name->c_str() == Token::COMMA.name->c_str()) {
//                                 lexer->nextToken();
//                                 continue;
//                             }

//                             break;
//                         }
//                     }
//                     stmt->addItem(item);
//                 }
//                 return BOOL::TRUE;
//             } else if (lexer->identifierEquals("BLOCK_SIZE")) {
//                 // Caution: Not in MySql documents.
//                 SQLAlterTableBlockSize* item = new SQLAlterTableBlockSize();
//                 lexer->nextToken();
//                 if (lexer->token()->name->c_str() == Token::EQ.name->c_str()) {
//                     accept(Token::EQ);
//                 }
//                 item.setSize((SQLIntegerExpr) exprParser->getExpr());
//                 stmt->addItem(item);
//                 return BOOL::TRUE;
//             } else if (lexer->identifierEquals(INSERT_METHOD)) {
//                 // Caution: Not in MySql documents.
//                 lexer->nextToken();
//                 if (lexer->token()->name->c_str() == Token::EQ.name->c_str()) {
//                     lexer->nextToken();
//                 }
//                 stmt->getTableOptions().add(new SQLAssignItem(new SQLIdentifierExpr(INSERT_METHOD), this->exprParser->primary()));
//                 return BOOL::TRUE;
//             } else if (lexer->identifierEquals(FnvHash::Constants::CLUSTERED)) {
//                 // Caution: Not in MySql documents.
//                 SQLAlterTableModifyClusteredBy* clusteredBy = new SQLAlterTableModifyClusteredBy();

//                 acceptIdentifier("CLUSTERED");
//                 accept(Token::BY);
//                 accept(Token::LPAREN);

//                 // for ads: ALTER TABLE SCHEMA1.TABLE1 CLUSTERED BY ();
//                 if (lexer->token()->name->c_str() != Token::RPAREN) {
//                     for (; ; ) {
//                         clusteredBy.addClusterColumn(this->exprParser->name());

//                         if (lexer->token()->name->c_str() == Token::COMMA.name->c_str()) {
//                             accept(Token::COMMA);
//                             continue;
//                         }
//                         break;
//                     }
//                 }

//                 accept(Token::RPAREN);

//                 stmt->addItem(clusteredBy);
//                 return BOOL::TRUE;
//             } else if (lexer->identifierEquals(FnvHash::Constants::SUBPARTITION_AVAILABLE_PARTITION_NUM)) {
//                 // Caution: Not in MySql documents.
//                 lexer->nextToken();
//                 if (lexer->token()->name->c_str() == Token::EQ.name->c_str()) {
//                     lexer->nextToken();
//                 }
//                 SQLIntegerExpr num = this->exprParser->integerExpr();
//                 SQLAlterTableSubpartitionAvailablePartitionNum* item = new SQLAlterTableSubpartitionAvailablePartitionNum();
//                 item.setNumber(num);
//                 stmt->addItem(item);
//                 return BOOL::TRUE;
//             }
//             break;
//     }
//     else if (lexer->token()->name->c_str() == Token::ALTER.name->c_str()) {
//             lexer->nextToken();
//             if (lexer->token()->name->c_str() == Token::INDEX) {
//                 // Caution: Not in MySql documents.
//                 lexer->nextToken();

//                 SQLName_ptr  indexName = this->exprParser->name();

//                 if (lexer->identifierEquals("VISIBLE")) {
//                     SQLAlterTableAlterIndex* alterIndex = new SQLAlterTableAlterIndex();
//                     alterIndex.setName(indexName);
//                     lexer->nextToken();
//                     alterIndex.getIndexDefinition().getOptions().setVisible(BOOL::TRUE);
//                     stmt->addItem(alterIndex);
//                     break;
//                 }

//                 MySqlAlterTableAlterFullTextIndex* alterIndex = new MySqlAlterTableAlterFullTextIndex();
//                 alterIndex.setIndexName(indexName);

//                 accept(Token::SET);
//                 accept(Token::FULLTEXT);

//                 if (lexer->token()->name->c_str() == Token::INDEX) {
//                     lexer->nextToken();
//                     alterIndex.setAnalyzerType(AnalyzerIndexType.INDEX);
//                 } else if (lexer->identifierEquals(FnvHash::Constants::QUERY)) {
//                     lexer->nextToken();
//                     alterIndex.setAnalyzerType(AnalyzerIndexType.QUERY);
//                 }

//                 acceptIdentifier("ANALYZER");

//                 accept(Token::EQ);

//                 alterIndex.setAnalyzerName(this->exprParser->name());
//                 stmt->addItem(alterIndex);
//             } else if (lexer->token()->name->c_str() == Token::CHECK || lexer->token()->name->c_str() == Token::CONSTRAINT.name->c_str()) {
//                 lexer->nextToken();
//                 MysqlAlterTableAlterCheck* check = new MysqlAlterTableAlterCheck();
//                 check.setName(this->exprParser->name());
//                 BOOL_ptr enforce = BOOL::TRUE;
//                 if (lexer->token()->name->c_str() == Token::NOT.name->c_str()) {
//                     enforce = BOOL::FALSE;
//                     lexer->nextToken();
//                 }
//                 if (StringUtils::iequals(lexer->stringVal(), "ENFORCED")) {
//                     check.setEnforced(enforce);
//                     lexer->nextToken();
//                 }
//                 stmt->addItem(check);
//             } else {
//                 // ALTER [COLUMN] col_name {SET DEFAULT literal | DROP DEFAULT}
//                 if (lexer->token()->name->c_str() == Token::COLUMN) {
//                     lexer->nextToken();
//                 }
//                 MySqlAlterTableAlterColumn* alterColumn = new MySqlAlterTableAlterColumn();
//                 alterColumn.setColumn(this->exprParser->name());
//                 if (lexer->token()->name->c_str() == Token::SET.name->c_str()) {
//                     lexer->nextToken();
//                     accept(Token::DEFAULT);
//                     alterColumn.setDefaultExpr(this->exprParser->getExpr());
//                 } else {
//                     accept(Token::DROP);
//                     accept(Token::DEFAULT);
//                     alterColumn.setDropDefault(BOOL::TRUE);
//                 }
//                 stmt->addItem(alterColumn);
//             }
//             return BOOL::TRUE;
//         }

//         // [DEFAULT] CHARACTER SET [=] charset_name [COLLATE [=] collation_name]
//         // parse in table options.

//     else if (lexer->token()->name->c_str() == Token::DISABLE.name->c_str()) {
//             lexer->nextToken();
//             if (lexer->token()->name->c_str() == Token::CONSTRAINT.name->c_str()) {
//                 // Caution: Not in MySql documents.
//                 lexer->nextToken();
//                 SQLAlterTableDisableConstraint* item = new SQLAlterTableDisableConstraint();
//                 item.setConstraintName(this->exprParser->name());
//                 stmt->addItem(item);
//             } else {
//                 // DISABLE KEYS
//                 acceptIdentifier("KEYS");
//                 SQLAlterTableDisableKeys* item = new SQLAlterTableDisableKeys();
//                 stmt->addItem(item);
//             }
//             return BOOL::TRUE;

//     } else if (lexer->token()->name->c_str() == Token::ENABLE.name->c_str()) {
//             lexer->nextToken();
//             if (lexer->token()->name->c_str() == Token::CONSTRAINT.name->c_str()) {
//                 // Caution: Not in MySql documents.
//                 lexer->nextToken();
//                 SQLAlterTableEnableConstraint* item = new SQLAlterTableEnableConstraint();
//                 item.setConstraintName(this->exprParser->name());
//                 stmt->addItem(item);
//             } else {
//                 // ENABLE KEYS
//                 acceptIdentifier("KEYS");
//                 SQLAlterTableEnableKeys item = new SQLAlterTableEnableKeys();
//                 stmt->addItem(item);
//             }
//             return BOOL::TRUE;

//     } else if (lexer->token()->name->c_str() == Token::LOCK) {
//             // LOCK [=] {DEFAULT|NONE|SHARED|EXCLUSIVE}
//             lexer->nextToken();
//             if (lexer->token()->name->c_str() == Token::EQ.name->c_str()) {
//                 lexer->nextToken();
//             }
//             MySqlAlterTableLock* item = new MySqlAlterTableLock();
//             item.setLockType(new SQLIdentifierExpr(lexer->stringVal()));
//             lexer->nextToken();
//             stmt->addItem(item);
//             return BOOL::TRUE;

//     } else if (lexer->token()->name->c_str() == Token::ORDER.name->c_str()) {
//             lexer->nextToken();
//             accept(Token::BY);
//             MySqlAlterTableOrderBy* item = new MySqlAlterTableOrderBy();
//             while (BOOL::TRUE) {
//                 if (lexer->token()->name->c_str() == Token::IDENTIFIER.name->c_str()) {
//                     SQLSelectOrderByItem column = this->exprParser->parseSelectOrderByItem();
//                     column.setParent(item);
//                     item.addColumn(column);
//                 } else {
//                     break;
//                 }
//                 if (lexer->token()->name->c_str() == Token::COMMA.name->c_str()) {
//                     lexer->nextToken();
//                 } else {
//                     break;
//                 }
//             }
//             stmt->addItem(item);
//             return BOOL::TRUE;
//     } else if (lexer->token()->name->c_str() == Token::WITH.name->c_str()) {
//             // WITH VALIDATION
//             lexer->nextToken();
//             acceptIdentifier("VALIDATION");
//             MySqlAlterTableValidation* item = new MySqlAlterTableValidation();
//             item.setWithValidation(BOOL::TRUE);
//             stmt->addItem(item);
//             return BOOL::TRUE;
//     } else if (lexer->token()->name->c_str() == Token::DROP) {
//             // DROP [COLUMN] col_name
//             // DROP {INDEX|KEY} index_name
//             // DROP PRIMARY KEY
//             // DROP FOREIGN KEY fk_symbol
//             // DROP PARTITION partition_names
//             // TODO: need check.
//             parseAlterDrop(stmt);
//             return BOOL::TRUE;

//     } else if (lexer->token()->name->c_str() == Token::TRUNCATE) {
//             // TRUNCATE PARTITION {partition_names | ALL}
//             lexer->nextToken();
//             accept(Token::PARTITION);
//             SQLAlterTableTruncatePartition* item = new SQLAlterTableTruncatePartition();
//             if (lexer->token()->name->c_str() == Token::ALL) {
//                 item.getPartitions().add(new SQLIdentifierExpr("ALL"));
//                 lexer->nextToken();
//             } else {
//                 this->exprParser->names(item.getPartitions(), item);
//             }
//             stmt->addItem(item);
//             return BOOL::TRUE;
//     } else if (lexer->token()->name->c_str() == Token::ANALYZE) {
//             // ANALYZE PARTITION {partition_names | ALL}
//             lexer->nextToken();
//             accept(Token::PARTITION);
//             SQLAlterTableAnalyzePartition* item = new SQLAlterTableAnalyzePartition();
//             if (lexer->token()->name->c_str() == Token::ALL) {
//                 lexer->nextToken();
//                 item.getPartitions().add(new SQLIdentifierExpr("ALL"));
//             } else {
//                 this->exprParser->names(item.getPartitions(), item);
//             }
//             stmt->addItem(item);
//             return BOOL::TRUE;
//     } else if (lexer->token()->name->c_str() == Token::CHECK.name->c_str()) {
//             // CHECK PARTITION {partition_names | ALL}
//             lexer->nextToken();
//             accept(Token::PARTITION);
//             SQLAlterTableCheckPartition* item = new SQLAlterTableCheckPartition();
//             if (lexer->token()->name->c_str() == Token::ALL) {
//                 lexer->nextToken();
//                 item.getPartitions().add(new SQLIdentifierExpr("ALL"));
//             } else {
//                 this->exprParser->names(item.getPartitions(), item);
//             }
//             stmt->addItem(item);
//             return BOOL::TRUE;
//     } else if (lexer->token()->name->c_str() == Token::OPTIMIZE) {
//             // OPTIMIZE PARTITION {partition_names | ALL}
//             lexer->nextToken();
//             accept(Token::PARTITION);
//             SQLAlterTableOptimizePartition* item = new SQLAlterTableOptimizePartition();
//             if (lexer->token()->name->c_str() == Token::ALL) {
//                 lexer->nextToken();
//                 item.getPartitions().add(new SQLIdentifierExpr("ALL"));
//             } else {
//                 this->exprParser->names(item.getPartitions(), item);
//             }
//             stmt->addItem(item);
//             return BOOL::TRUE;
//         }

//         //
//         // Other not in MySql documents.
//         //

//     else if (lexer->token()->name->c_str() == Token::SET.name->c_str()) {
//             lexer->nextToken();

//             if (lexer->identifierEquals(FnvHash::Constants::RULE)) {
//                 SQLAlterTableSetOption* setOption = new SQLAlterTableSetOption();
//                 SQLAssignItem item = this->exprParser->parseAssignItem();
//                 setOption.addOption(item);
//                 stmt->addItem(setOption);
//             } else {
//                 acceptIdentifier("TBLPROPERTIES");
//                 SQLAlterTableSetOption* setOption = new SQLAlterTableSetOption();
//                 accept(Token::LPAREN);
//                 for (; ; ) {
//                     SQLAssignItem item = this->exprParser->parseAssignItem();
//                     setOption.addOption(item);
//                     if (lexer->token()->name->c_str() == Token::COMMA.name->c_str()) {
//                         lexer->nextToken();
//                         continue;
//                     }
//                     break;
//                 }
//                 accept(Token::RPAREN);
//                 stmt->addItem(setOption);

//                 if (lexer->token()->name->c_str() == Token::ON.name->c_str()) {
//                     lexer->nextToken();
//                     SQLName_ptr  on = this->exprParser->name();
//                     setOption.setOn(on);
//                 }
//             }

//             return BOOL::TRUE;
//     } else if (lexer->token()->name->c_str() == Token::PARTITION.name->c_str()) {
//             Lexer::SavePoint mark = lexer->mark();
//             lexer->nextToken();
//             if (lexer->identifierEquals(FnvHash::Constants::LIFECYCLE)) {
//                 lexer->nextToken();
//                 SQLAlterTablePartitionLifecycle* item = new SQLAlterTablePartitionLifecycle();
//                 if (lexer->token()->name->c_str() == Token::EQ.name->c_str()) {
//                     lexer->nextToken();
//                 }
//                 item.setLifecycle((SQLIntegerExpr) exprParser->integerExpr());
//                 stmt->addItem(item);
//                 return BOOL::TRUE;
//             } else {
//                 lexer->reset(mark);
//             }

//     }
//     return BOOL::FALSE;
// }

SQLStatement_ptr MySqlStatementParser::parseAlterTable(BOOL_ptr ignore, BOOL_ptr online, BOOL_ptr offline)
{
  lexer->nextToken();

  // SQLAlterTableStatement* stmt = new SQLAlterTableStatement(getDbType());
  // stmt->setIgnore(ignore);
  // stmt->setOnline(online);
  // stmt->setOffline(offline);
  // stmt->setName(this->exprParser->name());

  // while (BOOL::TRUE) {
  // BOOL_ptr parsed = ((MySqlExprParser) this->exprParser).parseTableOptions(stmt->getTableOptions(), stmt);
  // if (!parsed) {
  //     parsed = parseAlterSpecification(stmt);
  // }

  // if (parsed) {
  //     if (lexer->token()->name->c_str() == Token::COMMA.name->c_str()) {
  //         lexer->nextToken();
  //     }
  // } else {
  //     break;
  // }
  // }

  // partition_options
  if (Token::PARTITION == *lexer->token())
  {
    // SQLPartitionBy* partitionBy = this->getSQLCreateTableParser().parsePartitionBy();
    // stmt->setPartition(partitionBy);
  }
  else
  {
    // Change to rename table if only one rename to xx.
    // if (1 == stmt->getItems().size() && stmt->getItems().get(0) instanceof SQLAlterTableRename) {
    //     MySqlRenameTableStatement *renameStmt = new MySqlRenameTableStatement();
    //     MySqlRenameTableStatement.Item item = new MySqlRenameTableStatement.Item();
    //     item.setName((SQLName_ptr ) stmt->getTableSource().getExpr());
    //     item.setTo(((SQLAlterTableRename) stmt->getItems().get(0)).getToName());
    //     renameStmt.addItem(item);
    //     return renameStmt;
    // }
  }

  // return stmt;
}

/*
SQLStatement_ptr  parseAlterTableOld(BOOL_ptr ignore) {
    lexer->nextToken();

    SQLAlterTableStatement stmt = new SQLAlterTableStatement(getDbType());
    stmt->setIgnore(ignore);
    stmt->setName(this->exprParser->name());

    for_:
    for (; ; ) {
        if (lexer->token()->name->c_str() == Token::COMMA.name->c_str()) {
            lexer->nextToken();
        }

        switch (*lexer->token()) {
            case DROP: {
                parseAlterDrop(stmt);
                break;
            }
            case TRUNCATE: {
                lexer->nextToken();
                accept(Token::PARTITION);

                SQLAlterTableTruncatePartition item = new SQLAlterTableTruncatePartition();
                if (lexer->token()->name->c_str() == Token::ALL) {
                    item.getPartitions().add(new SQLIdentifierExpr("ALL"));
                    lexer->nextToken();
                } else {
                    this->exprParser->names(item.getPartitions(), item);
                }
                stmt->addItem(item);
                break;
            }
            case ALTER: {
                lexer->nextToken();
                if (lexer->token()->name->c_str() == Token::INDEX) {
                    lexer->nextToken();
                    MySqlAlterTableAlterFullTextIndex alterIndex = new MySqlAlterTableAlterFullTextIndex();
                    SQLName_ptr  indexName = this->exprParser->name();
                    alterIndex.setIndexName(indexName);

                    accept(Token::SET);
                    accept(Token::FULLTEXT);

                    if (lexer->token()->name->c_str() == Token::INDEX) {
                        lexer->nextToken();
                        alterIndex.setAnalyzerType(AnalyzerIndexType.INDEX);
                    } else if (lexer->identifierEquals(FnvHash::Constants::QUERY)) {
                        lexer->nextToken();
                        alterIndex.setAnalyzerType(AnalyzerIndexType.QUERY);
                    }

                    acceptIdentifier("ANALYZER");

                    accept(Token::EQ);

                    alterIndex.setAnalyzerName(this->exprParser->name());
                    stmt->addItem(alterIndex);
                } else {
                    if (lexer->token()->name->c_str() == Token::COLUMN) {
                        lexer->nextToken();
                    }

                    MySqlAlterTableAlterColumn alterColumn = new MySqlAlterTableAlterColumn();
                    alterColumn.setColumn(this->exprParser->name());

                    if (lexer->token()->name->c_str() == Token::SET.name->c_str()) {
                        lexer->nextToken();
                        accept(Token::DEFAULT);

                        alterColumn.setDefaultExpr(this->exprParser->getExpr());
                    } else {
                        accept(Token::DROP);
                        accept(Token::DEFAULT);
                        alterColumn.setDropDefault(BOOL::TRUE);
                    }

                    stmt->addItem(alterColumn);
                }
                break;
            }
            case DISABLE: {
                lexer->nextToken();
                if (lexer->token()->name->c_str() == Token::CONSTRAINT.name->c_str()) {
                    lexer->nextToken();
                    SQLAlterTableDisableConstraint item = new SQLAlterTableDisableConstraint();
                    item.setConstraintName(this->exprParser->name());
                    stmt->addItem(item);
                } else {
                    acceptIdentifier("KEYS");
                    SQLAlterTableDisableKeys item = new SQLAlterTableDisableKeys();
                    stmt->addItem(item);
                }
                break;
            }
            case ENABLE: {
                lexer->nextToken();
                if (lexer->token()->name->c_str() == Token::CONSTRAINT.name->c_str()) {
                    lexer->nextToken();
                    SQLAlterTableEnableConstraint item = new SQLAlterTableEnableConstraint();
                    item.setConstraintName(this->exprParser->name());
                    stmt->addItem(item);
                } else {
                    acceptIdentifier("KEYS");
                    SQLAlterTableEnableKeys item = new SQLAlterTableEnableKeys();
                    stmt->addItem(item);
                }
                break;
            }
            case DEFAULT: {
                lexer->nextToken();
                if (lexer->identifierEquals(FnvHash::Constants::CHARACTER)) {
                    SQLAlterCharacter item = alterTableCharacter();
                    stmt->addItem(item);
                } else if (lexer->identifierEquals(FnvHash::Constants::COLLATE)) {
                    lexer->nextToken();
                    if (lexer->token()->name->c_str() == Token::EQ.name->c_str()) {
                        lexer->nextToken();
                    }
                    SQLAlterCharacter item = new SQLAlterCharacter();
                    item.setCollate(this->exprParser->primary());
                    stmt->addItem(item);
                } else {
                    throw new ParserException("TODO " + lexer->info());
                }
                continue for_;
            }
            case CHECK: {
                lexer->nextToken();
                accept(Token::PARTITION);

                SQLAlterTableCheckPartition item = new SQLAlterTableCheckPartition();

                if (lexer->token()->name->c_str() == Token::ALL) {
                    lexer->nextToken();
                    item.getPartitions().add(new SQLIdentifierExpr("ALL"));
                } else {
                    this->exprParser->names(item.getPartitions(), item);
                }

                stmt->addItem(item);
                break;
            }
            case OPTIMIZE: {
                lexer->nextToken();

                accept(Token::PARTITION);

                SQLAlterTableOptimizePartition item = new SQLAlterTableOptimizePartition();

                if (lexer->token()->name->c_str() == Token::ALL) {
                    lexer->nextToken();
                    item.getPartitions().add(new SQLIdentifierExpr("ALL"));
                } else {
                    this->exprParser->names(item.getPartitions(), item);
                }

                stmt->addItem(item);
                break;
            }
            case ANALYZE: {
                lexer->nextToken();
                accept(Token::PARTITION);

                SQLAlterTableAnalyzePartition item = new SQLAlterTableAnalyzePartition();

                if (lexer->token()->name->c_str() == Token::ALL) {
                    lexer->nextToken();
                    item.getPartitions().add(new SQLIdentifierExpr("ALL"));
                } else {
                    this->exprParser->names(item.getPartitions(), item);
                }
                stmt->addItem(item);
                break;
            }
            case COMMENT: {
                lexer->nextToken();
                if (lexer->token()->name->c_str() == Token::EQ.name->c_str()) {
                    accept(Token::EQ);
                }
                stmt->getTableOptions().put("COMMENT", this->exprParser->charExpr());
                continue for_;
            }
            case UNION: {
                lexer->nextToken();
                if (lexer->token()->name->c_str() == Token::EQ.name->c_str()) {
                    lexer->nextToken();
                }

                accept(Token::LPAREN);
                SQLTableSource tableSrc = this->createSQLSelectParser().parseTableSource();
                stmt->getTableOptions().put("UNION", tableSrc);
                accept(Token::RPAREN);
                continue for_;
            }
            case SET: {
                lexer->nextToken();

                if (lexer->identifierEquals(FnvHash::Constants::RULE)) {
                    SQLAlterTableSetOption setOption = new SQLAlterTableSetOption();
                    SQLAssignItem item = this->exprParser->parseAssignItem();
                    setOption.addOption(item);
                    stmt->addItem(setOption);
                } else {
                    acceptIdentifier("TBLPROPERTIES");
                    SQLAlterTableSetOption setOption = new SQLAlterTableSetOption();
                    accept(Token::LPAREN);
                    for (; ; ) {
                        SQLAssignItem item = this->exprParser->parseAssignItem();
                        setOption.addOption(item);
                        if (lexer->token()->name->c_str() == Token::COMMA.name->c_str()) {
                            lexer->nextToken();
                            continue;
                        }
                        break;
                    }
                    accept(Token::RPAREN);
                    stmt->addItem(setOption);

                    if (lexer->token()->name->c_str() == Token::ON.name->c_str()) {
                        lexer->nextToken();
                        SQLName_ptr  on = this->exprParser->name();
                        setOption.setOn(on);
                    }
                }

                break;
            }
            default: {
                if (lexer->identifierEquals(FnvHash::Constants::ADD)) {
                    lexer->nextToken();

                    if (lexer->token()->name->c_str() == Token::COLUMN) {
                        lexer->nextToken();
                        parseAlterTableAddColumn(stmt);
                    } else if (lexer->token()->name->c_str() == Token::INDEX
                            || lexer->token()->name->c_str() == Token::FULLTEXT
                            || lexer->identifierEquals(FnvHash::Constants::SPATIAL)
                            || lexer->identifierEquals(FnvHash::Constants::CLUSTERED)
                            || lexer->identifierEquals(FnvHash::Constants::ANN)
                            || lexer->identifierEquals(FnvHash::Constants::GLOBAL)
                            || lexer->identifierEquals(FnvHash::Constants::LOCAL)) {
                        SQLAlterTableAddIndex item = parseAlterTableAddIndex();
                        item.setParent(stmt);
                        stmt->addItem(item);
                    } else if (lexer->token()->name->c_str() == Token::UNIQUE) {
                        SQLAlterTableAddIndex item = parseAlterTableAddIndex();
                        item.setParent(stmt);
                        stmt->addItem(item);
                    } else if (lexer->token()->name->c_str() == Token::PRIMARY) {
                        SQLPrimaryKey primaryKey = this->exprParser->parsePrimaryKey();
                        SQLAlterTableAddConstraint item = new SQLAlterTableAddConstraint(primaryKey);
                        stmt->addItem(item);
                    } else if (lexer->token()->name->c_str() == Token::KEY) {
                        // throw new ParserException("TODO " + lexer->token() +
                        // " " + lexer->stringVal());
                        SQLAlterTableAddIndex item = parseAlterTableAddIndex();
                        item.setParent(stmt);
                        stmt->addItem(item);
                    } else if (lexer->identifierEquals(FnvHash::Constants::CLUSTERING)) {
                        SQLAlterTableAddClusteringKey item = parseAlterTableAddClusteringKey();
                        item.setParent(stmt);
                        stmt->addItem(item);
                    } else if (lexer->token()->name->c_str() == Token::FOREIGN) {
                        MysqlForeignKey fk = this->getExprParser().parseForeignKey();
                        SQLAlterTableAddConstraint item = new SQLAlterTableAddConstraint(fk);

                        stmt->addItem(item);
                    } else if (lexer->token()->name->c_str() == Token::CONSTRAINT.name->c_str()) {
                        lexer->nextToken();

                        if (lexer->token()->name->c_str() == Token::PRIMARY) {
                            SQLPrimaryKey primaryKey = ((MySqlExprParser) this->exprParser).parsePrimaryKey();
                            SQLAlterTableAddConstraint item = new SQLAlterTableAddConstraint(primaryKey);
                            item.setParent(stmt);

                            stmt->addItem(item);
                        } else if (lexer->token()->name->c_str() == Token::FOREIGN) {
                            MysqlForeignKey fk = this->getExprParser().parseForeignKey();
                            fk.setHasConstraint(BOOL::TRUE);

                            SQLAlterTableAddConstraint item = new SQLAlterTableAddConstraint(fk);

                            stmt->addItem(item);
                        } else if (lexer->token()->name->c_str() == Token::UNIQUE) {
                            SQLUnique unique = this->exprParser->parseUnique();
                            SQLAlterTableAddConstraint item = new SQLAlterTableAddConstraint(unique);
                            stmt->addItem(item);
                        } else {
                            SQLName_ptr  constraintName = this->exprParser->name();

                            if (lexer->token()->name->c_str() == Token::PRIMARY) {
                                SQLPrimaryKey primaryKey = ((MySqlExprParser) this->exprParser).parsePrimaryKey();

                                primaryKey.setName(constraintName);

                                SQLAlterTableAddConstraint item = new SQLAlterTableAddConstraint(primaryKey);
                                item.setParent(stmt);

                                stmt->addItem(item);
                            } else if (lexer->token()->name->c_str() == Token::FOREIGN) {
                                MysqlForeignKey fk = this->getExprParser().parseForeignKey();
                                fk.setName(constraintName);
                                fk.setHasConstraint(BOOL::TRUE);

                                SQLAlterTableAddConstraint item = new SQLAlterTableAddConstraint(fk);

                                stmt->addItem(item);
                            } else if (lexer->token()->name->c_str() == Token::UNIQUE) {
                                SQLUnique unique = this->exprParser->parseUnique();
                                SQLAlterTableAddConstraint item = new SQLAlterTableAddConstraint(unique);
                                stmt->addItem(item);
                            } else {
                                throw new ParserException("TODO " + lexer->info());
                            }
                        }
                    } else if (lexer->token()->name->c_str() == Token::PARTITION.name->c_str()) {
                        lexer->nextToken();

                        SQLAlterTableAddPartition item = new SQLAlterTableAddPartition();

                        if (lexer->identifierEquals(make_string_ptr("PARTITIONS"))) {
                            lexer->nextToken();
                            item.setPartitionCount(this->exprParser->integerExpr());
                        }

                        if (lexer->token()->name->c_str() == Token::LPAREN.name->c_str()) {
                            lexer->nextToken();
                            SQLPartition partition = this->getExprParser().parsePartition();
                            accept(Token::RPAREN);
                            item.addPartition(partition);
                        }

                        stmt->addItem(item);
                    } else if (lexer->identifierEquals(FnvHash::Constants::EXTPARTITION)) {
                        lexer->nextToken();
                        accept(Token::LPAREN);
                        SQLAlterTableAddExtPartition extPartitionItem = new SQLAlterTableAddExtPartition();
                        MySqlExtPartition partitionDef = parseExtPartition();
                        extPartitionItem.setExPartition(partitionDef);
                        stmt->addItem(extPartitionItem);
                        accept(Token::RPAREN);
                    } else {
                        parseAlterTableAddColumn(stmt);
                    }
                } else if (lexer->identifierEquals(FnvHash::Constants::CHANGE)) {
                    lexer->nextToken();
                    if (lexer->token()->name->c_str() == Token::COLUMN) {
                        lexer->nextToken();
                    }
                    MySqlAlterTableChangeColumn item = new MySqlAlterTableChangeColumn();
                    item.setColumnName(this->exprParser->name());
                    item.setNewColumnDefinition(this->exprParser->parseColumn());
                    if (lexer->identifierEquals("AFTER")) {
                        lexer->nextToken();
                        item.setAfterColumn(this->exprParser->name());
                    } else if (lexer->identifierEquals("FIRST")) {
                        lexer->nextToken();
                        if (lexer->token()->name->c_str() == Token::IDENTIFIER.name->c_str()) {
                            item.setFirstColumn(this->exprParser->name());
                        } else {
                            item.setFirst(BOOL::TRUE);
                        }
                    }
                    stmt->addItem(item);
                } else if (lexer->identifierEquals(FnvHash::Constants::MODIFY)) {
                    lexer->nextToken();

                    if (lexer->token()->name->c_str() == Token::COLUMN) {
                        lexer->nextToken();
                    }

                    BOOL_ptr paren = BOOL::FALSE;
                    if (lexer->token()->name->c_str() == Token::LPAREN.name->c_str()) {
                        paren = BOOL::TRUE;
                        lexer->nextToken();
                    }

                    for (; ; ) {
                        MySqlAlterTableModifyColumn item = new MySqlAlterTableModifyColumn();
                        item.setNewColumnDefinition(this->exprParser->parseColumn());
                        if (lexer->identifierEquals("AFTER")) {
                            lexer->nextToken();
                            item.setAfterColumn(this->exprParser->name());
                        } else if (lexer->identifierEquals("FIRST")) {
                            lexer->nextToken();
                            if (lexer->token()->name->c_str() == Token::IDENTIFIER.name->c_str()) {
                                item.setFirstColumn(this->exprParser->name());
                            } else {
                                item.setFirst(BOOL::TRUE);
                            }
                        }
                        stmt->addItem(item);

                        if (paren && lexer->token() == Token::COMMA.name->c_str()) {
                            lexer->nextToken();
                            continue;
                        }
                        break;
                    }

                    if (paren) {
                        accept(Token::RPAREN);
                    }
                } else if (lexer->identifierEquals(FnvHash::Constants::RENAME)) {
                    lexer->nextToken();

                    if (lexer->token()->name->c_str() == Token::INDEX) {
                        lexer->nextToken();
                        SQLName_ptr  name = this->exprParser->name();
                        accept(Token::TO);
                        SQLName_ptr  to = this->exprParser->name();
                        SQLAlterTableRenameIndex item = new SQLAlterTableRenameIndex(name, to);
                        stmt->addItem(item);
                        continue for_;
                    }

                    if (lexer->token()->name->c_str() == Token::COLUMN) {
                        lexer->nextToken();

                        SQLName_ptr  columnName = exprParser->name();
                        accept(Token::TO);
                        SQLName_ptr  toName = this->exprParser->name();
                        SQLAlterTableRenameColumn renameColumn = new SQLAlterTableRenameColumn();

                        renameColumn.setColumn(columnName);
                        renameColumn.setTo(toName);
                        stmt->addItem(renameColumn);
                        continue for_;
                    }

                    if (lexer->token()->name->c_str() == Token::TO || lexer->token()->name->c_str() == Token::AS) {
                        lexer->nextToken();
                    }

                    if (stmt->getItems().size() > 0) {
                        SQLAlterTableRename item = new SQLAlterTableRename();
                        SQLName_ptr  to = this->exprParser->name();
                        item.setTo(to);
                        stmt->addItem(item);
                    } else {
                        MySqlRenameTableStatement renameStmt = new MySqlRenameTableStatement();
                        MySqlRenameTableStatement.Item item = new MySqlRenameTableStatement.Item();
                        item.setName((SQLName_ptr ) stmt->getTableSource().getExpr());
                        item.setTo(this->exprParser->name());
                        renameStmt.addItem(item);

                        if (lexer->token()->name->c_str() == Token::COMMA.name->c_str()) {
                            lexer->nextToken();

                            SQLAlterTableRename alterItem = new SQLAlterTableRename();
                            alterItem.setTo(item.getTo());
                            stmt->addItem(alterItem);
                            continue;
                        } else {
                            // SQLAlterTableRename
                            return renameStmt;
                        }

                    }
                } else if (lexer->token()->name->c_str() == Token::ORDER.name->c_str()) {
                    throw new ParserException("TODO " + lexer->info());
                } else if (lexer->identifierEquals("CONVERT")) {
                    lexer->nextToken();
                    accept(Token::TO);
                    acceptIdentifier("CHARACTER");
                    accept(Token::SET);

                    SQLAlterTableConvertCharSet item = new SQLAlterTableConvertCharSet();
                    SQLExpr_ptr charset = this->exprParser->primary();
                    item.setCharset(charset);

                    if (lexer->identifierEquals("COLLATE")) {
                        lexer->nextToken();
                        SQLExpr_ptr collate = this->exprParser->primary();
                        item.setCollate(collate);
                    }

                    stmt->addItem(item);
                } else if (lexer->identifierEquals(FnvHash::Constants::DISCARD)) {
                    lexer->nextToken();

                    if (lexer->token()->name->c_str() == Token::PARTITION.name->c_str()) {
                        lexer->nextToken();
                        SQLAlterTableDiscardPartition item = new SQLAlterTableDiscardPartition();

                        if (lexer->token()->name->c_str() == Token::ALL) {
                            lexer->nextToken();
                            item.getPartitions().add(new SQLIdentifierExpr("ALL"));
                        } else {
                            this->exprParser->names(item.getPartitions(), item);
                        }

                        if (lexer->token()->name->c_str() == Token::TABLESPACE.name->c_str()) {
                            lexer->nextToken();
                            item.setTablespace(BOOL::TRUE);
                        }

                        stmt->addItem(item);
                    } else {
                        accept(Token::TABLESPACE);
                        MySqlAlterTableDiscardTablespace item = new MySqlAlterTableDiscardTablespace();
                        stmt->addItem(item);
                    }

                } else if (lexer->identifierEquals("IMPORT")) {
                    lexer->nextToken();

                    if (lexer->token()->name->c_str() == Token::PARTITION.name->c_str()) {
                        lexer->nextToken();
                        SQLAlterTableImportPartition item = new SQLAlterTableImportPartition();

                        if (lexer->token()->name->c_str() == Token::ALL) {
                            lexer->nextToken();
                            item.getPartitions().add(new SQLIdentifierExpr("ALL"));
                        } else {
                            this->exprParser->names(item.getPartitions(), item);
                        }

                        stmt->addItem(item);
                    } else {
                        accept(Token::TABLESPACE);
                        MySqlAlterTableImportTablespace item = new MySqlAlterTableImportTablespace();
                        stmt->addItem(item);
                    }
                } else if (lexer->identifierEquals(FnvHash::Constants::FORCE)) {
                    throw new ParserException("TODO " + lexer->info());
                } else if (lexer->identifierEquals("COALESCE")) {
                    lexer->nextToken();
                    accept(Token::PARTITION);

                    SQLAlterTableCoalescePartition item = new SQLAlterTableCoalescePartition();
                    SQLIntegerExpr countExpr = this->exprParser->integerExpr();
                    item.setCount(countExpr);
                    stmt->addItem(item);
                } else if (lexer->identifierEquals("REORGANIZE")) {
                    lexer->nextToken();
                    accept(Token::PARTITION);

                    SQLAlterTableReOrganizePartition item = new SQLAlterTableReOrganizePartition();

                    this->exprParser->names(item.getNames(), item);

                    accept(Token::INTO);
                    accept(Token::LPAREN);
                    for (; ; ) {
                        SQLPartition partition = this->getExprParser().parsePartition();

                        item.addPartition(partition);

                        if (lexer->token()->name->c_str() == Token::COMMA.name->c_str()) {
                            lexer->nextToken();
                            continue;
                        } else {
                            break;
                        }
                    }
                    accept(Token::RPAREN);
                    stmt->addItem(item);
                } else if (lexer->identifierEquals(FnvHash::Constants::EXCHANGE)) {
                    lexer->nextToken();
                    accept(Token::PARTITION);

                    SQLAlterTableExchangePartition item = new SQLAlterTableExchangePartition();

                    SQLName_ptr  partition = this->exprParser->name();
                    item.addPartition(partition);

                    accept(Token::WITH);
                    accept(Token::TABLE);
                    SQLName_ptr  table = this->exprParser->name();
                    item.setTable(table);

                    if (lexer->token()->name->c_str() == Token::WITH.name->c_str()) {
                        lexer->nextToken();
                        acceptIdentifier("VALIDATION");
                        item.setValidation(BOOL::TRUE);
                    } else if (lexer->identifierEquals(FnvHash::Constants::WITHOUT)) {
                        lexer->nextToken();
                        acceptIdentifier("VALIDATION");
                        item.setValidation(BOOL::FALSE);
                    }

                    stmt->addItem(item);
                } else if (lexer->identifierEquals("REBUILD")) {
                    lexer->nextToken();

                    accept(Token::PARTITION);

                    SQLAlterTableRebuildPartition item = new SQLAlterTableRebuildPartition();

                    if (lexer->token()->name->c_str() == Token::ALL) {
                        lexer->nextToken();
                        item.getPartitions().add(new SQLIdentifierExpr("ALL"));
                    } else {
                        this->exprParser->names(item.getPartitions(), item);
                    }

                    stmt->addItem(item);
                } else if (lexer->identifierEquals("REPAIR")) {
                    lexer->nextToken();

                    accept(Token::PARTITION);

                    SQLAlterTableRepairPartition item = new SQLAlterTableRepairPartition();

                    if (lexer->token()->name->c_str() == Token::ALL) {
                        lexer->nextToken();
                        item.getPartitions().add(new SQLIdentifierExpr("ALL"));
                    } else {
                        this->exprParser->names(item.getPartitions(), item);
                    }

                    stmt->addItem(item);
                } else if (lexer->identifierEquals(FnvHash::Constants::PARTITIONS)) {
                    SQLAlterTablePartitionCount item = new SQLAlterTablePartitionCount();
                    lexer->nextToken();
                    if (lexer->token()->name->c_str() == Token::EQ.name->c_str()) {
                        lexer->nextToken();
                    }
                    item.setCount((SQLIntegerExpr) exprParser->integerExpr());
                    stmt->addItem(item);
                } else if (lexer->token()->name->c_str() == Token::PARTITION.name->c_str()) {
                    lexer->nextToken();
                    if(lexer->identifierEquals(FnvHash::Constants::LIFECYCLE)) {
                        lexer->nextToken();
                        SQLAlterTablePartitionLifecycle item = new SQLAlterTablePartitionLifecycle();
                        if (lexer->token()->name->c_str() == Token::EQ.name->c_str()) {
                            lexer->nextToken();
                        }
                        item.setLifecycle((SQLIntegerExpr) exprParser->integerExpr());
                        stmt->addItem(item);
                    }
                } else if (lexer->identifierEquals(FnvHash::Constants::SUBPARTITION)) {
                    lexer->nextToken();
                    if (lexer->identifierEquals(FnvHash::Constants::LIFECYCLE)) {
                        lexer->nextToken();
                        SQLAlterTableSubpartitionLifecycle item = new SQLAlterTableSubpartitionLifecycle();
                        if (lexer->token()->name->c_str() == Token::LITERAL_INT) {
                            for (; ; ) {
                                item.getPartitionIds().add(this->exprParser->integerExpr());
                                string_ptr  pidStr = lexer->stringVal();
                                accept(Token::VARIANT);
                                string_ptr  s = pidStr.replaceAll(":", "");
                                if (StringUtils.isEmpty(s)) {
                                    item.getSubpartitionLifeCycle().add(exprParser->integerExpr());
                                } else {
                                    item.getSubpartitionLifeCycle().add(new SQLIntegerExpr(Integer.valueOf(s)));
                                }

                                if (lexer->token()->name->c_str() == Token::COMMA.name->c_str()) {
                                    lexer->nextToken();
                                    continue;
                                }

                                break;
                            }
                        }
                        stmt->addItem(item);
                    }
                } else if (lexer->identifierEquals("BLOCK_SIZE")) {
                    SQLAlterTableBlockSize item = new SQLAlterTableBlockSize();
                    lexer->nextToken();
                    if (lexer->token()->name->c_str() == Token::EQ.name->c_str()) {
                        accept(Token::EQ);
                    }
                    item.setSize((SQLIntegerExpr) exprParser->getExpr());
                    stmt->addItem(item);
                } else if (lexer->identifierEquals("COMPRESSION")) {
                    SQLAlterTableCompression item = new SQLAlterTableCompression();
                    lexer->nextToken();
                    if (lexer->token()->name->c_str() == Token::EQ.name->c_str()) {
                        lexer->nextToken();
                    }
                    item.setName(exprParser->charExpr());
                    stmt->addItem(item);
                    continue for_;
                } else if (lexer->identifierEquals("REMOVE")) {
                    lexer->nextToken();
                    acceptIdentifier("PARTITIONING");
                    stmt->setRemovePatiting(BOOL::TRUE);
                } else if (lexer->identifierEquals(make_string_ptr("UPGRADE"))) {
                    lexer->nextToken();
                    acceptIdentifier("PARTITIONING");
                    stmt->setUpgradePatiting(BOOL::TRUE);
                } else if (lexer->identifierEquals(make_string_ptr("ALGORITHM"))) {
                    lexer->nextToken();
                    if (lexer->token()->name->c_str() == Token::EQ.name->c_str()) {
                        lexer->nextToken();
                    }
                    stmt->addItem(new MySqlAlterTableOption("ALGORITHM", lexer->stringVal()));
                    lexer->nextToken();
                    continue for_;
                } else if (lexer->identifierEquals(ENGINE)) {
                    lexer->nextToken();
                    if (lexer->token()->name->c_str() == Token::EQ.name->c_str()) {
                        lexer->nextToken();
                    }
                    stmt->getTableOptions().put(ENGINE, this->exprParser->primary());
                    continue for_;
                } else if (lexer->identifierEquals(AUTO_INCREMENT)) {
                    lexer->nextToken();
                    if (lexer->token()->name->c_str() == Token::EQ.name->c_str()) {
                        lexer->nextToken();
                    }
                    stmt->getTableOptions().put(AUTO_INCREMENT, this->exprParser->integerExpr());
                    continue for_;
                } else if (lexer->identifierEquals(AVG_ROW_LENGTH)) {
                    lexer->nextToken();
                    if (lexer->token()->name->c_str() == Token::EQ.name->c_str()) {
                        lexer->nextToken();
                    }
                    stmt->getTableOptions().put(AVG_ROW_LENGTH, this->exprParser->integerExpr());
                    continue for_;
                } else if (lexer->identifierEquals(FnvHash::Constants::CHECKSUM)) {
                    lexer->nextToken();
                    if (lexer->token()->name->c_str() == Token::EQ.name->c_str()) {
                        lexer->nextToken();
                    }
                    stmt->getTableOptions().put(CHECKSUM2, this->exprParser->integerExpr());
                    continue for_;
                } else if (lexer->identifierEquals(FnvHash::Constants::CONNECTION)) {
                    lexer->nextToken();
                    if (lexer->token()->name->c_str() == Token::EQ.name->c_str()) {
                        lexer->nextToken();
                    }
                    stmt->getTableOptions().put(CONNECTION, this->exprParser->charExpr());
                    continue for_;
                } else if (lexer->identifierEquals(FnvHash::Constants::DATA) ||
                        lexer->token() == Token::INDEX) {
                    BOOL_ptr isIndex = lexer->token() == Token::INDEX;
                    lexer->nextToken();
                    acceptIdentifier("DIRECTORY");
                    if (lexer->token()->name->c_str() == Token::EQ.name->c_str()) {
                        lexer->nextToken();
                    }
                    stmt->getTableOptions().put(
                            isIndex ? "INDEX DIRECTORY" : "DATA DIRECTORY",
                            this->exprParser->primary());
                    continue for_;
                } else if (lexer->identifierEquals(DELAY_KEY_WRITE)) {
                    lexer->nextToken();
                    if (lexer->token()->name->c_str() == Token::EQ.name->c_str()) {
                        lexer->nextToken();
                    }
                    stmt->getTableOptions().put(DELAY_KEY_WRITE, this->exprParser->integerExpr());
                    continue for_;
                } else if (lexer->identifierEquals(FnvHash::Constants::ENCRYPTION)) {
                    lexer->nextToken();
                    if (lexer->token()->name->c_str() == Token::EQ.name->c_str()) {
                        lexer->nextToken();
                    }
                    stmt->getTableOptions().put(ENCRYPTION2, this->exprParser->primary());
                    continue for_;
                } else if (lexer->identifierEquals(INSERT_METHOD)) {
                    lexer->nextToken();
                    if (lexer->token()->name->c_str() == Token::EQ.name->c_str()) {
                        lexer->nextToken();
                    }
                    stmt->getTableOptions().put(INSERT_METHOD, this->exprParser->primary());
                    continue for_;
                } else if (lexer->identifierEquals(FnvHash::Constants::KEY_BLOCK_SIZE)) {
                    lexer->nextToken();
                    if (lexer->token()->name->c_str() == Token::EQ.name->c_str()) {
                        lexer->nextToken();
                    }
                    stmt->getTableOptions().put(KEY_BLOCK_SIZE2, this->exprParser->integerExpr());
                    continue for_;
                } else if (lexer->identifierEquals(FnvHash::Constants::MAX_ROWS)) {
                    lexer->nextToken();
                    if (lexer->token()->name->c_str() == Token::EQ.name->c_str()) {
                        lexer->nextToken();
                    }
                    stmt->getTableOptions().put(MAX_ROWS2, this->exprParser->integerExpr());
                    continue for_;
                } else if (lexer->identifierEquals(FnvHash::Constants::MIN_ROWS)) {
                    lexer->nextToken();
                    if (lexer->token()->name->c_str() == Token::EQ.name->c_str()) {
                        lexer->nextToken();
                    }
                    stmt->getTableOptions().put(MIN_ROWS2, this->exprParser->integerExpr());
                    continue for_;
                } else if (lexer->identifierEquals(FnvHash::Constants::PASSWORD)) {
                    lexer->nextToken();
                    if (lexer->token()->name->c_str() == Token::EQ.name->c_str()) {
                        lexer->nextToken();
                    }
                    stmt->getTableOptions().put(PASSWORD2, this->exprParser->primary());
                    continue for_;
                } else if (lexer->identifierEquals(STATS_AUTO_RECALC)) {
                    lexer->nextToken();
                        lexer->nextToken();
                    }
                    stmt->getTableOptions().put(STATS_AUTO_RECALC, this->exprParser->primary());
                    continue for_;
                } else if (lexer->identifierEquals(STATS_PERSISTENT)) {
                    lexer->nextToken();
                    if (lexer->token()->name->c_str() == Token::EQ.name->c_str()) {
                        lexer->nextToken();
                    }
                    stmt->getTableOptions().put(STATS_PERSISTENT, this->exprParser->primary());
                    continue for_;
                } else if (lexer->identifierEquals(STATS_SAMPLE_PAGES)) {
                    lexer->nextToken();
                    if (lexer->token()->name->c_str() == Token::EQ.name->c_str()) {
                        lexer->nextToken();
                    }
                    stmt->getTableOptions().put(STATS_SAMPLE_PAGES, this->exprParser->integerExpr());
                    continue for_;
                } else if (lexer->token()->name->c_str() == Token::TABLESPACE.name->c_str()) {
                    lexer->nextToken();
                    MySqlCreateTableStatement.TableSpaceOption option = new MySqlCreateTableStatement.TableSpaceOption();
                    option.setName(this->exprParser->name());
                    if (lexer->identifierEquals(make_string_ptr("STORAGE"))) {
                        lexer->nextToken();
                        option.setStorage(this->exprParser->name());
                    }
                    stmt->addItem(new MySqlAlterTableOption(TABLESPACE2, option));
                    continue for_;
                } else if (lexer->identifierEquals(FnvHash::Constants::COLLATE)) {
                    lexer->nextToken();
                    if (lexer->token()->name->c_str() == Token::EQ.name->c_str()) {
                        lexer->nextToken();
                    }
                    SQLAlterCharacter item = new SQLAlterCharacter();
                    item.setCollate(this->exprParser->primary());
                    stmt->addItem(item);
                    continue for_;
                } else if (lexer->identifierEquals("PACK_KEYS")) {
                    lexer->nextToken();
                    if (lexer->token()->name->c_str() == Token::EQ.name->c_str()) {
                        lexer->nextToken();
                    }
                    if (lexer->identifierEquals("PACK")) {
                        lexer->nextToken();
                        accept(Token::ALL);
                        stmt->getTableOptions().put("PACK_KEYS", new SQLIdentifierExpr("PACK ALL"));
                    } else {
                        stmt->getTableOptions().put("PACK_KEYS", this->exprParser->primary());
                    }
                    continue for_;
                } else if (lexer->identifierEquals(FnvHash::Constants::CHARACTER)) {
                    SQLAlterCharacter item = alterTableCharacter();
                    stmt->addItem(item);
                    continue for_;
                } else if (lexer->identifierEquals(FnvHash::Constants::CLUSTERED)) {
                    SQLAlterTableModifyClusteredBy clusteredBy = new SQLAlterTableModifyClusteredBy();

                    acceptIdentifier("CLUSTERED");
                    accept(Token::BY);
                    accept(Token::LPAREN);

                    // for ads: ALTER TABLE SCHEMA1.TABLE1 CLUSTERED BY ();
                    if (lexer->token()->name->c_str() != Token::RPAREN) {
                        for (; ; ) {
                            clusteredBy.addClusterColumn(this->exprParser->name());

                            if (lexer->token()->name->c_str() == Token::COMMA.name->c_str()) {
                                accept(Token::COMMA);
                                continue;
                            }
                            break;
                        }
                    }

                    accept(Token::RPAREN);

                    stmt->addItem(clusteredBy);
                } else if (lexer->identifierEquals("ROW_FORMAT")) {
                    lexer->nextToken();
                    if (lexer->token()->name->c_str() == Token::EQ.name->c_str()) {
                        lexer->nextToken();
                    }

                    if (lexer->token()->name->c_str() == Token::DEFAULT || lexer->token()->name->c_str() == Token::IDENTIFIER.name->c_str()) {
                        SQLIdentifierExpr rowFormat = new SQLIdentifierExpr(lexer->stringVal());
                        lexer->nextToken();
                        stmt->getTableOptions().put("ROW_FORMAT", rowFormat);
                    } else {
                        throw new ParserException("illegal syntax. " + lexer->info());
                    }

                    continue for_;
                } else if (lexer->identifierEquals(FnvHash::Constants::SUBPARTITION_AVAILABLE_PARTITION_NUM)) {
                    lexer->nextToken();
                    if (lexer->token()->name->c_str() == Token::EQ.name->c_str()) {
                        lexer->nextToken();
                    }
                    SQLIntegerExpr num = this->exprParser->integerExpr();
                    SQLAlterTableSubpartitionAvailablePartitionNum item = new SQLAlterTableSubpartitionAvailablePartitionNum();
                    item.setNumber(num);
                    stmt->addItem(item);
                } else if (lexer->token()->name->c_str() == Token::LOCK) {
                    lexer->nextToken();
                    if (lexer->token()->name->c_str() == Token::EQ.name->c_str()) {
                        lexer->nextToken();
                    }
                    SQLIdentifierExpr rowFormat = new SQLIdentifierExpr(lexer->stringVal());
                    lexer->nextToken();
                    stmt->getTableOptions().put("LOCK", rowFormat);
                } else {
                    break for_;
                }
                break;
            }
        }

        if (lexer->token()->name->c_str() == Token::COMMA.name->c_str()) {
            lexer->nextToken();
            continue;
        } else {
            break;
        }

    }

    return stmt;
}
*/

// MySqlExtPartition* MySqlStatementParser::parseExtPartition() {
//     MySqlExtPartition partitionDef = new MySqlExtPartition();
//     for (; ; ) {
//         MySqlExtPartition.Item item = new MySqlExtPartition.Item();

//         if (lexer->identifierEquals(FnvHash::Constants::DBPARTITION)) {
//             lexer->nextToken();
//             SQLName_ptr  name = this->exprParser->name();
//             item.setDbPartition(name);
//             accept(Token::BY);
//             SQLExpr_ptr value = this->exprParser->primary();
//             item.setDbPartitionBy(value);
//         }

//         if (lexer->identifierEquals(FnvHash::Constants::TBPARTITION)) {
//             lexer->nextToken();
//             SQLName_ptr  name = this->exprParser->name();
//             item.setTbPartition(name);
//             accept(Token::BY);
//             SQLExpr_ptr value = this->exprParser->primary();
//             item.setTbPartitionBy(value);
//         }

//         item.setParent(partitionDef);
//         partitionDef.getItems().add(item);

//         if (lexer->token()->name->c_str() == Token::COMMA.name->c_str()) {
//             lexer->nextToken();
//             continue;
//         } else {
//             break;
//         }
//     }

//     return partitionDef;
// }

// SQLAlterCharacter* MySqlStatementParser::alterTableCharacter() {
//     lexer->nextToken();
//     accept(Token::SET);
//     if (lexer->token()->name->c_str() == Token::EQ.name->c_str()) {
//         lexer->nextToken();
//     }
//     SQLAlterCharacter item = new SQLAlterCharacter();
//     item.setCharacterSet(this->exprParser->primary());
//     if (lexer->token()->name->c_str() == Token::COMMA.name->c_str()) {
//         lexer->nextToken();
//         if (lexer->identifierEquals(FnvHash::Constants::COLLATE)) {
//             lexer->nextToken();
//             if (lexer->token()->name->c_str() == Token::EQ.name->c_str()) {
//                 lexer->nextToken();
//             }
//             item.setCollate(this->exprParser->primary());
//         }
//     }
//     return item;
// }

// void MySqlStatementParser::parseAlterTableAddColumn(SQLAlterTableStatement* stmt) {
//     BOOL_ptr parenFlag = BOOL::FALSE;
//     if (lexer->token()->name->c_str() == Token::LPAREN.name->c_str()) {
//         lexer->nextToken();
//         parenFlag = BOOL::TRUE;
//     }

//     SQLAlterTableAddColumn item = new SQLAlterTableAddColumn();
//     for (; ; ) {
//         SQLColumnDefinition columnDef = this->exprParser->parseColumn();
//         item.addColumn(columnDef);
//         if (lexer->identifierEquals("AFTER")) {
//             lexer->nextToken();
//             item.setAfterColumn(this->exprParser->name());
//         } else if (lexer->identifierEquals("FIRST")) {
//             lexer->nextToken();
//             if (lexer->token()->name->c_str() == Token::IDENTIFIER.name->c_str()) {
//                 item.setFirstColumn(this->exprParser->name());
//             } else {
//                 item.setFirst(BOOL::TRUE);
//             }
//         }

//         if (parenFlag && lexer->token() == Token::COMMA.name->c_str()) {
//             lexer->nextToken();
//             continue;
//         }

//         break;
//     }

//     if (parenFlag) {
//         accept(Token::RPAREN);
//     }

//     if (lexer->identifierEquals(FnvHash::Constants::RESTRICT)) {
//         lexer->nextToken();
//         item.setRestrict(BOOL::TRUE);
//     } else if (lexer->token()->name->c_str() == Token::CASCADE || lexer->identifierEquals(FnvHash::Constants::CASCADE)) {
//         lexer->nextToken();
//         item.setCascade(BOOL::TRUE);
//     } else {
//         item.setCascade(BOOL::FALSE);
//     }

//     stmt->addItem(item);
// }

// void MySqlStatementParser::parseAlterDrop(SQLAlterTableStatement* stmt) {
//     lexer->nextToken();
//     if (lexer->token()->name->c_str() == Token::INDEX) {
//         lexer->nextToken();
//         SQLName_ptr  indexName = this->exprParser->name();
//         SQLAlterTableDropIndex item = new SQLAlterTableDropIndex();
//         item.setIndexName(indexName);
//         stmt->addItem(item);
//     } else if (lexer->token()->name->c_str() == Token::FOREIGN) {
//         lexer->nextToken();
//         accept(Token::KEY);
//         SQLName_ptr  indexName = this->exprParser->name();
//         SQLAlterTableDropForeignKey item = new SQLAlterTableDropForeignKey();
//         item.setIndexName(indexName);
//         stmt->addItem(item);
//     } else if (lexer->token()->name->c_str() == Token::KEY) {
//         lexer->nextToken();
//         SQLName_ptr  keyName = this->exprParser->name();
//         SQLAlterTableDropKey item = new SQLAlterTableDropKey();
//         item.setKeyName(keyName);
//         stmt->addItem(item);
//     } else if (lexer->token()->name->c_str() == Token::PRIMARY) {
//         lexer->nextToken();
//         accept(Token::KEY);
//         SQLAlterTableDropPrimaryKey item = new SQLAlterTableDropPrimaryKey();
//         stmt->addItem(item);
//     } else if (lexer->token()->name->c_str() == Token::CONSTRAINT.name->c_str()) {
//         lexer->nextToken();
//         SQLAlterTableDropConstraint item = new SQLAlterTableDropConstraint();
//         item.setConstraintName(this->exprParser->name());
//         stmt->addItem(item);
//     } else if (lexer->token()->name->c_str() == Token::COLUMN) {
//         lexer->nextToken();
//         SQLAlterTableDropColumnItem item = new SQLAlterTableDropColumnItem();

//         SQLName_ptr  name = exprParser->name();
//         name.setParent(item);
//         item.addColumn(name);

//         if (dbType != DbType::mysql) {
//             while (lexer->token()->name->c_str() == Token::COMMA.name->c_str()) {
//                 Lexer::SavePoint savePoint = lexer->markOut();
//                 lexer->nextToken();
//                 if (lexer->identifierEquals(FnvHash::Constants::CHANGE)
//                         || lexer->identifierEquals(FnvHash::Constants::MODIFY)) {
//                     lexer->reset(savePoint);
//                     break;
//                 }

//                 if (lexer->token()->name->c_str() == Token::IDENTIFIER.name->c_str()) {
//                     if (StringUtils::iequals("ADD", lexer->stringVal())) {
//                         lexer->reset(savePoint);
//                         break;
//                     }
//                     name = exprParser->name();
//                     name.setParent(item);
//                     item.addColumn(name);
//                 } else {
//                     lexer->reset(savePoint);
//                     break;
//                 }
//             }
//         }

//         stmt->addItem(item);
//     } else if (lexer->token()->name->c_str() == Token::PARTITION.name->c_str()) {
//         SQLAlterTableDropPartition dropPartition = parseAlterTableDropPartition(BOOL::FALSE);
//         stmt->addItem(dropPartition);
//     } else if (lexer->identifierEquals(FnvHash::Constants::SUBPARTITION)) {
//         SQLAlterTableDropSubpartition dropPartition = parseAlterTableDropSubpartition();
//         stmt->addItem(dropPartition);
//     } else if (lexer->identifierEquals(FnvHash::Constants::CLUSTERING) || lexer->identifierEquals(FnvHash::Constants::CLUSTERED)) {
//         lexer->nextToken();
//         SQLAlterTableDropClusteringKey dropPartition = new SQLAlterTableDropClusteringKey();
//         accept(Token::KEY);
//         dropPartition.setKeyName(exprParser->name());
//         stmt->addItem(dropPartition);
//     } else if (lexer->token()->name->c_str() == Token::IDENTIFIER.name->c_str()) {
//         if (lexer->identifierEquals(FnvHash::Constants::EXTPARTITION)) {
//             lexer->nextToken();
//             accept(Token::LPAREN);
//             SQLAlterTableDropExtPartition extPartitionItem = new SQLAlterTableDropExtPartition();
//             MySqlExtPartition partitionDef = parseExtPartition();
//             extPartitionItem.setExPartition(partitionDef);
//             stmt->addItem(extPartitionItem);
//             accept(Token::RPAREN);
//         } else {
//             SQLAlterTableDropColumnItem item = new SQLAlterTableDropColumnItem();

//             SQLName_ptr  name = this->exprParser->name();
//             item.addColumn(name);
//             stmt->addItem(item);

//             if (lexer->token()->name->c_str() == Token::COMMA.name->c_str()) {
//                 lexer->nextToken();
//             }

//             if (lexer->token()->name->c_str() == Token::DROP) {
//                 parseAlterDrop(stmt);
//             }
//         }
//     } else {
//         super.parseAlterDrop(stmt);
//     }
// }

SQLStatement_ptr MySqlStatementParser::parseRename()
{
  acceptIdentifier("RENAME");

  if (lexer->token()->name->c_str() == Token::SEQUENCE.name->c_str())
  {
    lexer->nextToken();
    // MySqlRenameSequenceStatement* stmt = new MySqlRenameSequenceStatement();

    SQLName_ptr name = this->exprParser->name();
    // stmt->setName(name);

    accept(Token::TO);

    SQLName_ptr to = this->exprParser->name();
    // stmt->setTo(to);

    // return stmt;
  }
  if (lexer->token()->name->c_str() == Token::USER.name->c_str())
  {
    lexer->nextToken();
    // SQLRenameUserStatement* stmt = new SQLRenameUserStatement();

    SQLName_ptr name = this->exprParser->name();
    // stmt->setName(name);

    accept(Token::TO);

    SQLName_ptr to = this->exprParser->name();
    // stmt->setTo(to);

    // return stmt;
  }

  accept(Token::TABLE);
  // MySqlRenameTableStatement* stmt = new MySqlRenameTableStatement();

  for (;;)
  {
    // MySqlRenameTableStatement.Item item = new MySqlRenameTableStatement.Item();
    // item.setName(this->exprParser->name());
    accept(Token::TO);
    // item.setTo(this->exprParser->name());

    // stmt->addItem(item);

    if (lexer->token()->name->c_str() == Token::COMMA.name->c_str())
    {
      lexer->nextToken();
      continue;
    }

    break;
  }

  // return stmt;
}

SQLStatement_ptr MySqlStatementParser::parseCreateDatabase()
{
  if (lexer->token()->name->c_str() == Token::CREATE.name->c_str())
  {
    lexer->nextToken();
  }

  if (lexer->token()->name->c_str() == Token::SCHEMA.name->c_str())
  {
    lexer->nextToken();
  }
  else
  {
    accept(Token::DATABASE);
  }

  SQLCreateDatabaseStatement_ptr stmt = SQLCreateDatabaseStatement_ptr(new SQLCreateDatabaseStatement(dbType));

  if (lexer->token()->name->c_str() == Token::HINT.name->c_str())
  {
    SQLCommentHint_list_ptr hints = this->exprParser->parseHints();
    if (hints->size() == 1)
    {
      auto it_hints = hints->begin();
      string_ptr text = (*it_hints)->getText();
      if (StringUtils::endWith(text, make_string_ptr(" IF NOT EXISTS")) && text->at(0) == '!')
      {
        stmt->setIfNotExists(BOOL::TRUE);
      }
    }
  }

  if (lexer->token()->name->c_str() == Token::IF.name->c_str())
  {
    lexer->nextToken();
    accept(Token::NOT);
    accept(Token::EXISTS);
    stmt->setIfNotExists(BOOL::TRUE);
  }

  stmt->setName(this->exprParser->name());

  if (lexer->token()->name->c_str() == Token::DEFAULT.name->c_str())
  {
    lexer->nextToken();
  }

  if (lexer->token()->name->c_str() == Token::HINT.name->c_str())
  {
    stmt->setHints(this->exprParser->parseHints());
  }

  if (lexer->token()->name->c_str() == Token::DEFAULT.name->c_str())
  {
    lexer->nextToken();
  }

  for (;;)
  {
    if (lexer->identifierEquals(FnvHash::Constants::CHARACTER))
    {
      lexer->nextToken();
      accept(Token::SET);
      if (lexer->token()->name->c_str() == Token::EQ.name->c_str())
      {
        lexer->nextToken();
      }
      string_ptr charset = make_string_ptr(encode_util::UnicodeToUTF8(*lexer->stringVal()));
      accept(Token::IDENTIFIER);
      stmt->setCharacterSet(charset);
    }
    else if (lexer->identifierEquals(FnvHash::Constants::CHARSET))
    {
      lexer->nextToken();
      if (lexer->token()->name->c_str() == Token::EQ.name->c_str())
      {
        lexer->nextToken();
      }
      string_ptr charset = make_string_ptr(encode_util::UnicodeToUTF8(*lexer->stringVal()));
      accept(Token::IDENTIFIER);
      stmt->setCharacterSet(charset);
    }
    else if (lexer->token()->name->c_str() == Token::DEFAULT.name->c_str())
    {
      lexer->nextToken();
    }
    else if (lexer->identifierEquals(FnvHash::Constants::COLLATE))
    {
      lexer->nextToken();
      if (lexer->token()->name->c_str() == Token::EQ.name->c_str())
      {
        lexer->nextToken();
      }
      string_ptr collate = make_string_ptr(encode_util::UnicodeToUTF8(*lexer->stringVal()));
      accept(Token::IDENTIFIER);
      stmt->setCollate(collate);
    }
    else if (lexer->identifierEquals(FnvHash::Constants::PASSWORD))
    {
      lexer->nextToken();
      if (lexer->token()->name->c_str() == Token::EQ.name->c_str())
      {
        lexer->nextToken();
      }
      SQLExpr_ptr password = this->exprParser->primary();
      stmt->setPassword(password);
    }
    // ads 特殊支持
    else if (lexer->identifierEquals(make_string_ptr("SHARDS")) ||
             lexer->identifierEquals(make_string_ptr("SHARD_ID")) ||
             lexer->identifierEquals(make_string_ptr("REPLICATION")) ||
             lexer->identifierEquals(make_string_ptr("STORAGE_DEPENDENCY")) ||
             lexer->identifierEquals(make_string_ptr("REPLICA_TYPE")) ||
             lexer->identifierEquals(make_string_ptr("DATA_REPLICATION")))
    {
      string_ptr key = make_string_ptr(encode_util::UnicodeToUTF8(*lexer->stringVal()));
      lexer->nextToken();
      accept(Token::EQ);
      SQLExpr_ptr value = this->exprParser->getExpr();
      stmt->getOptions()->insert(std::pair<string_ptr, SQLExpr_ptr>(key, value));
    }
    else
    {
      break;
    }
  }

  if (lexer->token()->name->c_str() == Token::FOR.name->c_str())
  {
    lexer->nextToken();
    string_ptr user = make_string_ptr(encode_util::UnicodeToUTF8(*lexer->stringVal()));
    lexer->nextToken();
    stmt->setUser(user);
  }

  if (lexer->identifierEquals(FnvHash::Constants::OPTIONS))
  {
    lexer->nextToken();
    accept(Token::LPAREN);
    for (;;)
    {
      if (lexer->token()->name->c_str() == Token::RPAREN.name->c_str())
      {
        accept(Token::RPAREN);
        break;
      }
      string_ptr key = make_string_ptr(encode_util::UnicodeToUTF8(*lexer->stringVal()));
      lexer->nextToken();
      accept(Token::EQ);
      SQLExpr_ptr value = this->exprParser->getExpr();
      stmt->getOptions()->insert(std::pair<string_ptr, SQLExpr_ptr>(key, value));
    }
  }

  if (lexer->token()->name->c_str() == Token::WITH.name->c_str())
  {
    lexer->nextToken();

    accept(Token::LPAREN);
    for (;;)
    {
      SQLAssignItem_ptr assignItem = this->exprParser->parseAssignItem();
      assignItem->setParent(stmt);
      stmt->getDbProperties()->push_back(assignItem);

      if (lexer->token()->name->c_str() == Token::COMMA.name->c_str())
      {
        lexer->nextToken();
        continue;
      }
      break;
    }
    accept(Token::RPAREN);
  }

  if (lexer->identifierEquals(FnvHash::Constants::STORED))
  {
    lexer->nextToken();

    if (lexer->token()->name->c_str() == Token::BY.name->c_str())
    {
      accept(Token::BY);

      for (;;)
      {
        SQLAssignItem_list_ptr storedByItem = std::make_shared<std::list<SQLAssignItem_ptr>>();
        accept(Token::LPAREN);
        for (;;)
        {
          SQLAssignItem_ptr assignItem = this->exprParser->parseAssignItem();
          assignItem->setParent(stmt);
          storedByItem->push_back(assignItem);

          if (lexer->token()->name->c_str() == Token::COMMA.name->c_str())
          {
            lexer->nextToken();
            continue;
          }
          break;
        }
        accept(Token::RPAREN);
        stmt->getStoredBy()->push_back(storedByItem);

        if (lexer->token()->name->c_str() == Token::COMMA.name->c_str())
        {
          lexer->nextToken();
          continue;
        }

        break;
      }
    }
    else if (lexer->token()->name->c_str() == Token::IN.name->c_str())
    {
      lexer->nextToken();

      stmt->setStoredIn(this->exprParser->name());

      accept(Token::ON);
      accept(Token::LPAREN);
      for (;;)
      {
        SQLAssignItem_ptr assignItem = this->exprParser->parseAssignItem();
        assignItem->setParent(stmt);
        stmt->getStoredOn()->push_back(assignItem);

        if (lexer->token()->name->c_str() == Token::COMMA.name->c_str())
        {
          lexer->nextToken();
          continue;
        }
        break;
      }
      accept(Token::RPAREN);
    }
    else if (lexer->token()->name->c_str() == Token::AS.name->c_str())
    {
      lexer->nextToken();
      SQLExpr_ptr like = this->exprParser->getExpr();
      stmt->setStoredAs(like);
    }
    else
    {
      throw new ParserException(make_string_ptr("TODO " + encode_util::UnicodeToUTF8(lexer->info())));
    }
  }

  return std::shared_ptr<SQLCreateDatabaseStatement>(stmt);
}

void MySqlStatementParser::parseUpdateSet(SQLUpdateStatement_ptr update)
{
  accept(Token::SET);

  for (;;)
  {
    SQLUpdateSetItem_ptr item = this->exprParser->parseUpdateSetItem();
    update->addItem(item);

    if (lexer->token()->name->c_str() != Token::COMMA.name->c_str())
    {
      break;
    }

    lexer->nextToken();
  }
}

SQLStatement_ptr MySqlStatementParser::parseAlterDatabase()
{
  if (lexer->token()->name->c_str() == Token::SCHEMA.name->c_str())
  {
    lexer->nextToken();
  }
  else
  {
    accept(Token::DATABASE);
  }

  // SQLAlterDatabaseStatement* stmt = new SQLAlterDatabaseStatement(dbType);

  SQLName_ptr name = this->exprParser->name();
  // stmt->setName(name);

  if (lexer->token()->name->c_str() == Token::SET.name->c_str())
  {
    lexer->nextToken();
    // MySqlAlterDatabaseSetOption* option = new MySqlAlterDatabaseSetOption();
    for (;;)
    {
      SQLName_ptr key = this->exprParser->name();
      accept(Token::EQ);
      SQLExpr_ptr value = this->exprParser->getExpr();

      // option.getOptions().add(new SQLAssignItem(key, value));

      if (lexer->token()->name->c_str() == Token::XEOF.name->c_str() || lexer->token()->name->c_str() == Token::ON.name->c_str())
      {
        break;
      }

      if (lexer->token()->name->c_str() == Token::COMMA.name->c_str())
      {
        lexer->nextToken();
      }
    }
    // stmt->setItem(option);

    if (lexer->token()->name->c_str() == Token::ON.name->c_str())
    {
      lexer->nextToken();
      SQLName_ptr on = this->exprParser->name();
      // option.setOn(on);
    }

    // return stmt;
  }

  if (lexer->token()->name->c_str() == Token::KILL.name->c_str())
  {
    // MySqlAlterDatabaseKillJob* item = new MySqlAlterDatabaseKillJob();
    lexer->nextToken();
    SQLName_ptr jobType = this->exprParser->name();
    SQLName_ptr jobId = this->exprParser->name();
    // item.setJobType(jobType);
    // item.setJobId(jobId);

    // stmt->setItem(item);
  }

  if (lexer->identifierEquals(make_string_ptr("UPGRADE")))
  {
    lexer->nextToken();
    acceptIdentifier("DATA");
    acceptIdentifier("DIRECTORY");
    acceptIdentifier("NAME");
    // stmt->setUpgradeDataDirectoryName(BOOL::TRUE);
  }

  if (lexer->token()->name->c_str() == Token::DEFAULT.name->c_str())
  {
    lexer->nextToken();
    if (lexer->identifierEquals(FnvHash::Constants::CHARACTER))
    {
      // SQLAlterCharacter item = alterTableCharacter();
      // stmt->setCharacter(item);
    }
    else
    {
      throw new ParserException(make_string_ptr("TODO " + encode_util::UnicodeToUTF8(lexer->info())));
    }
  }
  else if (lexer->identifierEquals(FnvHash::Constants::CHARACTER))
  {
    // SQLAlterCharacter item = alterTableCharacter();
    // stmt->setCharacter(item);
  }

  // return stmt;
}

// MySqlAlterUserStatement* MySqlStatementParser::parseAlterUser() {
//     accept(Token::USER);

//     MySqlAlterUserStatement* stmt = new MySqlAlterUserStatement();

//     if (lexer->token()->name->c_str() == Token::IF.name->c_str()) {
//         lexer->nextToken();
//         accept(Token::EXISTS);
//         stmt->setIfExists(BOOL::TRUE);
//     }

//     for (; ; ) {
//         MySqlAlterUserStatement.AlterUser alterUser = new MySqlAlterUserStatement.AlterUser();

//         SQLExpr_ptr user = this->exprParser->getExpr();
//         alterUser.setUser(user);

//         if (lexer->identifierEquals("IDENTIFIED")) {
//             lexer->nextToken();
//             accept(Token::BY);

//             MySqlAlterUserStatement.AuthOption authOption = new MySqlAlterUserStatement.AuthOption();
//             SQLCharExpr authstd::string = this->exprParser->charExpr();
//             authOption.setAuthstd::string(authstd::string);

//             alterUser.setAuthOption(authOption);
//         }

//         if (lexer->identifierEquals("PASSWORD")) {
//             lexer->nextToken();
//             if (lexer->identifierEquals("EXPIRE")) {
//                 lexer->nextToken();

//                 MySqlAlterUserStatement.PasswordOption passwordOption = new MySqlAlterUserStatement.PasswordOption();

//                 if (lexer->token()->name->c_str() == Token::DEFAULT) {
//                     lexer->nextToken();
//                     passwordOption.setExpire(MySqlAlterUserStatement.PasswordExpire.PASSWORD_EXPIRE_DEFAULT);
//                 } else if (lexer->identifierEquals("NEVER")) {
//                     lexer->nextToken();
//                     passwordOption.setExpire(MySqlAlterUserStatement.PasswordExpire.PASSWORD_EXPIRE_NEVER);
//                 } else if (lexer->token()->name->c_str() == Token::INTERVAL) {
//                     lexer->nextToken();
//                     passwordOption.setExpire(MySqlAlterUserStatement.PasswordExpire.PASSWORD_EXPIRE_INTERVAL);
//                     SQLIntegerExpr days = this->exprParser->integerExpr();
//                     passwordOption.setIntervalDays(days);
//                     acceptIdentifier("DAY");
//                 } else {
//                     passwordOption.setExpire(MySqlAlterUserStatement.PasswordExpire.PASSWORD_EXPIRE);
//                 }
//                 stmt->setPasswordOption(passwordOption);
//             }
//         }

//         stmt->getAlterUsers().add(alterUser);

//         if (lexer->token()->name->c_str() == Token::COMMA.name->c_str()) {
//             lexer->nextToken();
//             continue;
//         }

//         break;
//     }
//     return stmt;
// }

// MySqlExprParser* MySqlStatementParser::getExprParser() {
//     return (MySqlExprParser) exprParser;
// }

// SQLCreateFunctionStatement* MySqlStatementParser::parseCreateFunction() {
//     SQLCreateFunctionStatement stmt = new SQLCreateFunctionStatement();
//     stmt->setDbType(dbType);

//     if (lexer->token()->name->c_str() == Token::CREATE.name->c_str()) {
//         lexer->nextToken();

//         if (lexer->token()->name->c_str() == Token::OR) {
//             lexer->nextToken();
//             accept(Token::REPLACE);
//             stmt->setOrReplace(BOOL::TRUE);
//         }
//     }

//     if (lexer->identifierEquals(FnvHash::Constants::DEFINER)) {
//         lexer->nextToken();
//         accept(Token::EQ);
//         SQLName_ptr  definer = this->getExprParser().userName();
//         stmt->setDefiner(definer);
//     }

//     accept(Token::FUNCTION);

//     stmt->setName(this->exprParser->name());

//     if (lexer->token()->name->c_str() == Token::LPAREN.name->c_str()) { // match "("
//         lexer->nextToken();
//         parserParameters(stmt->getParameters(), stmt);
//         accept(Token::RPAREN); // match ")"
//     }

//     acceptIdentifier("RETURNS");
//     SQLDataType dataType = this->exprParser->parseDataType();
//     stmt->setReturnDataType(dataType);

//     for (; ; ) {
//         if (lexer->identifierEquals("DETERMINISTIC")) {
//             lexer->nextToken();
//             stmt->setDeterministic(BOOL::TRUE);
//             continue;
//         }

//         if (lexer->identifierEquals("DETERMINISTIC")) {
//             lexer->nextToken();
//             stmt->setDeterministic(BOOL::TRUE);
//             continue;
//         }

//         if (lexer->token()->name->c_str() == Token::COMMENT.name->c_str()) {
//             lexer->nextToken();
//             stmt->setComment(lexer->stringVal());
//             lexer->nextToken();
//             continue;
//         }

//         if (lexer->identifierEquals("LANGUAGE")) {
//             lexer->nextToken();
//             stmt->setLanguage(lexer->stringVal());
//             lexer->nextToken();
//             continue;
//         }

//         break;
//     }

//     SQLStatement_ptr  block;
//     if (lexer->token()->name->c_str() == Token::BEGIN.name->c_str()) {
//         block = this->parseBlock();
//     } else {
//         block = this->parseStatement();
//     }

//     stmt->setBlock(block);

//     return stmt;
// }

/*
 * parse create procedure statement
 */
// SQLCreateProcedureStatement* MySqlStatementParser::parseCreateProcedure() {
//     /*
//      * CREATE OR REPALCE PROCEDURE SP_NAME(parameter_list) BEGIN block_statement END
//      */
//     SQLCreateProcedureStatement stmt = new SQLCreateProcedureStatement();
//     stmt->setDbType(dbType);

//     if (lexer->token()->name->c_str() == Token::CREATE.name->c_str()) {
//         lexer->nextToken();

//         if (lexer->token()->name->c_str() == Token::OR) {
//             lexer->nextToken();
//             accept(Token::REPLACE);
//             stmt->setOrReplace(BOOL::TRUE);
//         }
//     }

//     if (lexer->identifierEquals(FnvHash::Constants::DEFINER)) {
//         lexer->nextToken();
//         accept(Token::EQ);
//         SQLName_ptr  definer = this->getExprParser().userName();
//         stmt->setDefiner(definer);
//     }

//     accept(Token::PROCEDURE);

//     stmt->setName(this->exprParser->name());

//     if (lexer->token()->name->c_str() == Token::LPAREN.name->c_str()) {
//         lexer->nextToken();
//         parserParameters(stmt->getParameters(), stmt);
//         accept(Token::RPAREN);
//     }

//     for (; ; ) {
//         if (lexer->token()->name->c_str() == Token::COMMENT.name->c_str()) {
//             lexer->nextToken();
//             stmt->setComment(this->exprParser->charExpr());
//         }
//         if (lexer->identifierEquals(FnvHash::Constants::LANGUAGE)) {
//             lexer->nextToken();
//             acceptIdentifier("SQL");
//             stmt->setLanguageSql(BOOL::TRUE);
//         }

//         if (lexer->identifierEquals(FnvHash::Constants::DETERMINISTIC)) {
//             lexer->nextToken();
//             stmt->setDeterministic(BOOL::TRUE);
//             continue;
//         }
//         if (lexer->identifierEquals(FnvHash::Constants::CONTAINS) || lexer->token()->name->c_str() == Token::CONTAINS) {
//             lexer->nextToken();
//             acceptIdentifier("SQL");
//             stmt->setContainsSql(BOOL::TRUE);
//             continue;
//         }

//         if (lexer->identifierEquals(FnvHash::Constants::SQL)) {
//             lexer->nextToken();
//             acceptIdentifier("SECURITY");
//             SQLName_ptr  authid = this->exprParser->name();
//             stmt->setAuthid(authid);
//         }

//         break;
//     }

//     SQLStatement_ptr  block;
//     if (lexer->token()->name->c_str() == Token::BEGIN.name->c_str()) {
//         block = this->parseBlock();
//     } else {
//         block = this->parseStatement();
//     }

//     stmt->setBlock(block);

//     return stmt;
// }

/*
 * parse create procedure parameters
 *
 * @param parameters
 */
// void MySqlStatementParser::parserParameters(std::list<SQLParameter*> parameters, SQLObject_ptr  parent) {
//     if (lexer->token()->name->c_str() == Token::RPAREN.name->c_str()) {
//         return;
//     }

//     for (; ; ) {
//         SQLParameter* parameter = new SQLParameter();

//         if (lexer->token()->name->c_str() == Token::CURSOR.name->c_str()) {
//             lexer->nextToken();

//             parameter.setName(this->exprParser->name());

//             accept(Token::IS);
//             SQLSelect* select = this->createSQLSelectParser().select();

//             SQLDataTypeImpl* dataType = new SQLDataTypeImpl();
//             dataType.setName("CURSOR");
//             parameter.setDataType(dataType);

//             parameter.setDefaultValue(new SQLQueryExpr(select));

//         } else if (lexer->token()->name->c_str() == Token::IN || lexer->token()->name->c_str() == Token::OUT || lexer->token()->name->c_str() == Token::INOUT) {
//             if (lexer->token()->name->c_str() == Token::IN) {
//                 parameter.setParamType(ParameterType.IN);
//             } else if (lexer->token()->name->c_str() == Token::OUT) {
//                 parameter.setParamType(ParameterType.OUT);
//             } else if (lexer->token()->name->c_str() == Token::INOUT) {
//                 parameter.setParamType(ParameterType.INOUT);
//             }
//             lexer->nextToken();

//             parameter.setName(this->exprParser->name());

//             parameter.setDataType(this->exprParser->parseDataType());
//         } else {
//             // default parameter type is in
//             parameter.setParamType(ParameterType.DEFAULT);
//             parameter.setName(this->exprParser->name());
//             parameter.setDataType(this->exprParser->parseDataType());

//             if (lexer->token()->name->c_str() == Token::COLONEQ) {
//                 lexer->nextToken();
//                 parameter.setDefaultValue(this->exprParser->getExpr());
//             }
//         }

//         parameters.add(parameter);
//         if (lexer->token()->name->c_str() == Token::COMMA || lexer->token()->name->c_str() == Token::SEMI.name->c_str()) {
//             lexer->nextToken();
//         }

//         if (lexer->token()->name->c_str() != Token::BEGIN && lexer->token() != Token::RPAREN) {
//             continue;
//         }

//         break;
//     }
// }

/*
 * parse procedure statement block
 *
 * @param statementList
 */
void MySqlStatementParser::parseProcedureStatementList(SQLStatement_list_ptr statementList)
{
  parseProcedureStatementList(statementList, -1);
}

/*
 * parse procedure statement block
 */
void MySqlStatementParser::parseProcedureStatementList(SQLStatement_list_ptr statementList, int max)
{
  for (;;)
  {
    if (max != -1)
    {
      if (statementList->size() >= max)
      {
        return;
      }
    }

    if (lexer->token()->name->c_str() == Token::XEOF.name->c_str())
    {
      return;
    }
    if (lexer->token()->name->c_str() == Token::END.name->c_str())
    {
      return;
    }
    if (lexer->token()->name->c_str() == Token::ELSE.name->c_str())
    {
      return;
    }
    if (lexer->token()->name->c_str() == (Token::SEMI.name->c_str()))
    {
      lexer->nextToken();
      continue;
    }
    if (lexer->token()->name->c_str() == Token::WHEN.name->c_str())
    {
      return;
    }
    if (lexer->token()->name->c_str() == Token::UNTIL.name->c_str())
    {
      return;
    }
    // select into
    if (lexer->token()->name->c_str() == (Token::SELECT.name->c_str()))
    {
      // statementList->push_back(this->parseSelectInto());
      continue;
    }

    // update
    if (lexer->token()->name->c_str() == (Token::UPDATE.name->c_str()))
    {
      // statementList->push_back(parseUpdateStatement());
      continue;
    }

    // create
    if (lexer->token()->name->c_str() == (Token::CREATE.name->c_str()))
    {
      statementList->push_back(parseCreate());
      continue;
    }

    // insert
    if (lexer->token()->name->c_str() == Token::INSERT.name->c_str())
    {
      SQLStatement_ptr stmt = parseInsert();
      statementList->push_back(stmt);
      continue;
    }

    // delete
    if (lexer->token()->name->c_str() == (Token::DELETE.name->c_str()))
    {
      // statementList->push_back(parseDeleteStatement());
      continue;
    }

    // call
    if (lexer->token()->name->c_str() == Token::LBRACE.name->c_str() || lexer->identifierEquals(make_string_ptr("CALL")))
    {
      // statementList->push_back(this->parseCall());
      continue;
    }

    // begin
    if (lexer->token()->name->c_str() == Token::BEGIN.name->c_str())
    {
      statementList->push_back(this->parseBlock());
      continue;
    }

    if (lexer->token()->name->c_str() == Token::VARIANT.name->c_str())
    {
      SQLExpr_ptr variant = this->exprParser->primary();
      if (instanceof <SQLExpr, SQLBinaryOpExpr>(variant))
      {
        SQLBinaryOpExpr_ptr binaryOpExpr = std::dynamic_pointer_cast<SQLBinaryOpExpr>(variant);
        if (binaryOpExpr->getOperator()->name->c_str() == SQLBinaryOperator::Assignment.name->c_str())
        {
          // SQLSetStatement* stmt = new SQLSetStatement(binaryOpExpr->getLeft(), binaryOpExpr->getRight(), getDbType());
          // statementList->push_back(stmt);
          continue;
        }
      }
      accept(Token::COLONEQ);
      SQLExpr_ptr value = this->exprParser->getExpr();

      // SQLSetStatement stmt = new SQLSetStatement(variant, value, getDbType());
      // statementList->push_back(stmt);
      continue;
    }

    // select
    if (lexer->token()->name->c_str() == Token::LPAREN.name->c_str())
    {
      Lexer_SavePoint_ptr savePoint = lexer->markOut();
      lexer->nextToken();

      if (lexer->token()->name->c_str() == Token::SELECT.name->c_str())
      {
        lexer->reset(savePoint);
        statementList->push_back(this->parseSelect());
        continue;
      }
      else
      {
        throw new ParserException(make_string_ptr("TODO. " + encode_util::UnicodeToUTF8(lexer->info())));
      }
    }
    // assign statement
    if (lexer->token()->name->c_str() == Token::SET.name->c_str())
    {
      // statementList->push_back(this->parseAssign());
      continue;
    }

    // while statement
    if (lexer->token()->name->c_str() == Token::WHILE.name->c_str())
    {
      // SQLStatement_ptr  stmt = this->parseWhile();
      // statementList->push_back(stmt);
      continue;
    }

    // loop statement
    if (lexer->token()->name->c_str() == Token::LOOP.name->c_str())
    {
      // statementList->push_back(this->parseLoop());
      continue;
    }

    // if statement
    if (lexer->token()->name->c_str() == Token::IF.name->c_str())
    {
      // statementList->push_back(this->parseIf());
      continue;
    }

    // case statement
    if (lexer->token()->name->c_str() == Token::CASE.name->c_str())
    {
      // statementList->push_back(this->parseCase());
      continue;
    }

    // declare statement
    if (lexer->token()->name->c_str() == Token::DECLARE.name->c_str())
    {
      SQLStatement_ptr stmt = this->parseDeclare();
      statementList->push_back(stmt);
      continue;
    }

    // leave statement
    if (lexer->token()->name->c_str() == Token::LEAVE.name->c_str())
    {
      // statementList->push_back(this->parseLeave());
      continue;
    }

    // iterate statement
    if (lexer->token()->name->c_str() == Token::ITERATE.name->c_str())
    {
      // statementList->push_back(this->parseIterate());
      continue;
    }

    // repeat statement
    if (lexer->token()->name->c_str() == Token::REPEAT.name->c_str())
    {
      // statementList->push_back(this->parseRepeat());
      continue;
    }

    // open cursor
    if (lexer->token()->name->c_str() == Token::OPEN.name->c_str())
    {
      // statementList->push_back(this->parseOpen());
      continue;
    }

    // close cursor
    if (lexer->token()->name->c_str() == Token::CLOSE.name->c_str())
    {
      // statementList->push_back(this->parseClose());
      continue;
    }

    // fetch cursor into
    if (lexer->token()->name->c_str() == Token::FETCH.name->c_str())
    {
      // statementList->push_back(this->parseFetch());
      continue;
    }

    if (lexer->identifierEquals(FnvHash::Constants::CHECKSUM))
    {
      // statementList->push_back(this->parseChecksum());
      continue;
    }

    if (lexer->token()->name->c_str() == Token::IDENTIFIER.name->c_str())
    {
      string_ptr label = make_string_ptr(encode_util::UnicodeToUTF8(*lexer->stringVal()));
      Lexer_SavePoint_ptr savePoint = lexer->markOut();
      lexer->nextToken();
      if (lexer->token()->name->c_str() == Token::VARIANT.name->c_str() &&
          (encode_util::UnicodeToUTF8(*lexer->stringVal()) == ":"))
      {
        lexer->nextToken();
        if (lexer->token()->name->c_str() == Token::LOOP.name->c_str())
        {
          // parse loop statement
          // statementList->push_back(this->parseLoop(label));
        }
        else if (lexer->token()->name->c_str() == Token::WHILE.name->c_str())
        {
          // parse while statement with label
          // statementList->push_back(this->parseWhile(label));
        }
        else if (lexer->token()->name->c_str() == Token::BEGIN.name->c_str())
        {
          // parse begin-end statement with label
          // statementList->push_back(this->parseBlock(label));
        }
        else if (lexer->token()->name->c_str() == Token::REPEAT.name->c_str())
        {
          // parse repeat statement with label
          // statementList->push_back(this->parseRepeat(label));
        }
        continue;
      }
      else
      {
        lexer->reset(savePoint);
      }
    }
    throw new ParserException(make_string_ptr("TODO, " + encode_util::UnicodeToUTF8(lexer->info())));
  }
}

// MySqlChecksumTableStatement* MySqlStatementParser::parseChecksum() {
//     MySqlChecksumTableStatement* stmt = new MySqlChecksumTableStatement();
//     if (lexer->identifierEquals(FnvHash::Constants::CHECKSUM)) {
//         lexer->nextToken();
//     } else {
//         throw new ParserException("TODO " + lexer->info());
//     }

//     accept(Token::TABLE);

//     for (; ; ) {
//         SQLName_ptr  table = this->exprParser->name();
//         stmt->addTable(new SQLExprTableSource(table));

//         if (lexer->token()->name->c_str() == Token::COMMA.name->c_str()) {
//             lexer->nextToken();
//             continue;
//         }

//         break;
//     }

//     return stmt;
// }

/*
 * parse if statement
 *
 * @return MySqlIfStatement
 */
SQLIfStatement *MySqlStatementParser::parseIf()
{
  accept(Token::IF);

  // SQLIfStatement* stmt = new SQLIfStatement();

  // stmt->setCondition(this->exprParser->getExpr());

  accept(Token::THEN);

  // this->parseStatementList(stmt->getStatements(), -1, stmt);

  while (lexer->token()->name->c_str() == Token::ELSE.name->c_str())
  {
    lexer->nextToken();

    if (lexer->token()->name->c_str() == Token::IF.name->c_str())
    {
      lexer->nextToken();

      // SQLIfStatement.ElseIf elseIf = new SQLIfStatement.ElseIf();

      // elseIf.setCondition(this->exprParser->getExpr());
      // elseIf.setParent(stmt);

      accept(Token::THEN);
      // this->parseStatementList(elseIf.getStatements(), -1, elseIf);

      // stmt->getElseIfstd::list().add(elseIf);
    }
    else
    {
      // SQLIfStatement.Else elseItem = new SQLIfStatement.Else();
      // this->parseStatementList(elseItem.getStatements(), -1, elseItem);
      // stmt->setElseItem(elseItem);
      break;
    }
  }

  accept(Token::END);
  accept(Token::IF);
  accept(Token::SEMI);
  // stmt->setAfterSemi(BOOL::TRUE);

  // return stmt;
}

/*
 * parse while statement
 *
 * @return MySqlWhileStatement
 */
SQLWhileStatement_ptr MySqlStatementParser::parseWhile()
{
  accept(Token::WHILE);
  SQLWhileStatement_ptr stmt = SQLWhileStatement_ptr(new SQLWhileStatement());

  stmt->setCondition(this->exprParser->getExpr());

  accept(Token::DO);

  this->parseStatementList(stmt->getStatements(), -1, stmt);

  accept(Token::END);

  accept(Token::WHILE);

  accept(Token::SEMI);

  stmt->setAfterSemi(BOOL::TRUE);

  return stmt;
}

/*
 * parse while statement with label
 *
 * @return MySqlWhileStatement
 */
SQLWhileStatement_ptr MySqlStatementParser::parseWhile(string_ptr label)
{
  accept(Token::WHILE);

  SQLWhileStatement_ptr stmt = SQLWhileStatement_ptr(new SQLWhileStatement());

  stmt->setLabelName(label);

  stmt->setCondition(this->exprParser->getExpr());

  accept(Token::DO);

  this->parseStatementList(stmt->getStatements(), -1, stmt);

  accept(Token::END);

  accept(Token::WHILE);

  acceptIdentifier(label);

  accept(Token::SEMI);

  stmt->setAfterSemi(BOOL::TRUE);

  return stmt;
}

/*
 * parse case statement
 *
 * @return MySqlCaseStatement
 */
// MySqlCaseStatement* MySqlStatementParser::parseCase() {
//     MySqlCaseStatement* stmt = new MySqlCaseStatement();
//     accept(Token::CASE);

//     if (lexer->token()->name->c_str() == Token::WHEN.name->c_str())// grammar 1
//     {
//         while (lexer->token()->name->c_str() == Token::WHEN.name->c_str()) {
//             MySqlWhenStatement when = new MySqlWhenStatement();

//             accept(Token::WHEN);

//             // when expr
//             when.setCondition(exprParser->getExpr());

//             accept(Token::THEN);

//             // when block
//             this->parseStatementList(when.getStatements(), -1, when);

//             stmt->addWhenStatement(when);
//         }
//         if (lexer->token()->name->c_str() == Token::ELSE.name->c_str()) {
//             // parse else block
//             SQLIfStatement.Else elseStmt = new SQLIfStatement.Else();
//             this->parseStatementList(elseStmt.getStatements(), -1, elseStmt);
//             stmt->setElseItem(elseStmt);
//         }
//     } else {
//         // case expr
//         stmt->setCondition(exprParser->getExpr());

//         while (lexer->token()->name->c_str() == Token::WHEN.name->c_str()) {
//             accept(Token::WHEN);
//             MySqlWhenStatement when = new MySqlWhenStatement();
//             // when expr
//             when.setCondition(exprParser->getExpr());

//             accept(Token::THEN);

//             // when block
//             this->parseStatementList(when.getStatements(), -1, when);

//             stmt->addWhenStatement(when);
//         }
//         if (lexer->token()->name->c_str() == Token::ELSE.name->c_str()) {
//             accept(Token::ELSE);
//             // else block
//             SQLIfStatement.Else elseStmt = new SQLIfStatement.Else();
//             this->parseStatementList(elseStmt.getStatements(), -1, elseStmt);
//             stmt->setElseItem(elseStmt);
//         }
//     }
//     accept(Token::END);
//     accept(Token::CASE);
//     accept(Token::SEMI);
//     return stmt;

// }

/*
 * parse declare statement
 */
SQLStatement_ptr MySqlStatementParser::parseDeclare()
{
  Lexer_SavePoint_ptr savePoint = lexer->markOut();

  lexer->nextToken();

  if (lexer->token()->name->c_str() == Token::CONTINUE.name->c_str())
  {
    lexer->reset(savePoint);
    // return this->parseDeclareHandler();
  }

  lexer->nextToken();
  if (lexer->token()->name->c_str() == Token::CURSOR.name->c_str())
  {
    lexer->reset(savePoint);
    // return this->parseCursorDeclare();
  }
  else if (lexer->identifierEquals(make_string_ptr("HANDLER")))
  {
    // DECLARE异常处理程序 [add by zhujun 2016-04-16]
    lexer->reset(savePoint);
    // return this->parseDeclareHandler();
  }
  else if (lexer->token()->name->c_str() == Token::CONDITION.name->c_str())
  {
    // DECLARE异常 [add by zhujun 2016-04-17]
    lexer->reset(savePoint);
    // return this->parseDeclareCondition();
  }
  else
  {
    lexer->reset(savePoint);
  }

  // MySqlDeclareStatement* stmt = new MySqlDeclareStatement();
  accept(Token::DECLARE);
  // lexer->nextToken();
  for (;;)
  {
    // SQLDeclareItem* item = new SQLDeclareItem();
    // item.setName(exprParser->name());

    // stmt->addVar(item);
    if (lexer->token()->name->c_str() == Token::COMMA.name->c_str())
    {
      lexer->nextToken();
      // stmt->setAfterSemi(BOOL::TRUE);
      continue;
    }
    else if (lexer->token()->name->c_str() != Token::XEOF.name->c_str())
    {
      // var type
      // item.setDataType(exprParser->parseDataType());

      if (lexer->token()->name->c_str() == Token::DEFAULT.name->c_str())
      {
        lexer->nextToken();
        SQLExpr_ptr defaultValue = this->exprParser->primary();
        // item.setValue(defaultValue);
      }

      break;
    }
    else
    {
      throw new ParserException(make_string_ptr("TODO. " + encode_util::UnicodeToUTF8(lexer->info())));
    }
  }
  // return stmt;
}

/*
 * parse assign statement
 */
// SQLSetStatement* MySqlStatementParser::parseAssign() {
//     accept(Token::SET);
//     SQLSetStatement* stmt = new SQLSetStatement(getDbType());
//     parseAssignItems(stmt->getItems(), stmt);
//     return stmt;
// }

/*
 * parse select into
 */
// MySqlSelectIntoStatement* MySqlStatementParser::parseSelectInto() {
//     MySqlSelectIntoParser* parse = new MySqlSelectIntoParser(this->exprParser);
//     return parse.parseSelectInto();
// }

/*
 * parse loop statement
 */
SQLLoopStatement_ptr MySqlStatementParser::parseLoop()
{
  SQLLoopStatement_ptr loopStmt = SQLLoopStatement_ptr(new SQLLoopStatement());
  accept(Token::LOOP);
  this->parseStatementList(loopStmt->getStatements(), -1, loopStmt);
  accept(Token::END);
  accept(Token::LOOP);
  accept(Token::SEMI);
  loopStmt->setAfterSemi(BOOL::TRUE);
  return loopStmt;
}

// /*
//  * parse loop statement with label
//  */
SQLLoopStatement_ptr MySqlStatementParser::parseLoop(string_ptr label)
{
  SQLLoopStatement_ptr loopStmt = SQLLoopStatement_ptr(new SQLLoopStatement());
  loopStmt->setLabelName(label);
  accept(Token::LOOP);
  this->parseStatementList(loopStmt->getStatements(), -1, loopStmt);
  accept(Token::END);
  accept(Token::LOOP);
  if (lexer->token()->name->c_str() != Token::SEMI.name->c_str())
  {
    acceptIdentifier(label);
  }
  accept(Token::SEMI);
  loopStmt->setAfterSemi(BOOL::TRUE);
  return loopStmt;
}

/*
 * parse loop statement with label
 */
SQLStatement_ptr MySqlStatementParser::parseBlock(string_ptr label)
{
  SQLBlockStatement_ptr block = SQLBlockStatement_ptr(new SQLBlockStatement());
  block->setLabelName(label);
  accept(Token::BEGIN);
  this->parseStatementList(block->getStatementList(), -1, block);
  accept(Token::END);
  acceptIdentifier(label);
  return block;
}

/*
 * parse leave statement
 */
// MySqlLeaveStatement* MySqlStatementParser::parseLeave() {
//     accept(Token::LEAVE);
//     MySqlLeaveStatement* leaveStmt = new MySqlLeaveStatement();
//     leaveStmt.setLabelName(exprParser->name().getSimpleName());
//     accept(Token::SEMI);
//     return leaveStmt;
// }

/*
 * parse iterate statement
 */
// MySqlIterateStatement* MySqlStatementParser::parseIterate() {
//     accept(Token::ITERATE);
//     MySqlIterateStatement* iterateStmt = new MySqlIterateStatement();
//     iterateStmt.setLabelName(exprParser->name().getSimpleName());
//     accept(Token::SEMI);
//     return iterateStmt;
// }

/*
 * parse repeat statement
 */
MySqlRepeatStatement_ptr MySqlStatementParser::parseRepeat()
{
  MySqlRepeatStatement_ptr stmt = MySqlRepeatStatement_ptr(new MySqlRepeatStatement());
  accept(Token::REPEAT);
  parseStatementList(stmt->getStatements(), -1, stmt);
  accept(Token::UNTIL);
  stmt->setCondition(exprParser->getExpr());
  accept(Token::END);
  accept(Token::REPEAT);
  accept(Token::SEMI);
  stmt->setAfterSemi(BOOL::TRUE);
  return stmt;
}

/*
 * parse repeat statement with label
 *
 * @param label
 */
MySqlRepeatStatement_ptr MySqlStatementParser::parseRepeat(string_ptr label)
{
  MySqlRepeatStatement_ptr repeatStmt = MySqlRepeatStatement_ptr(new MySqlRepeatStatement());
  repeatStmt->setLabelName(label);
  accept(Token::REPEAT);
  this->parseStatementList(repeatStmt->getStatements(), -1, repeatStmt);
  accept(Token::UNTIL);
  repeatStmt->setCondition(exprParser->getExpr());
  accept(Token::END);
  accept(Token::REPEAT);
  acceptIdentifier(label);
  accept(Token::SEMI);
  return repeatStmt;
}

/*
 * parse cursor declare statement
 */
// MySqlCursorDeclareStatement* MySqlStatementParser::parseCursorDeclare() {
// MySqlCursorDeclareStatement* stmt = new MySqlCursorDeclareStatement();
// accept(Token::DECLARE);

// stmt->setCursorName(exprParser->name());

// accept(Token::CURSOR);

// accept(Token::FOR);

// //SQLSelectStatement selelctStmt = (SQLSelectStatement) parseSelect();
// SQLSelect select = this->createSQLSelectParser().select();
// stmt->setSelect(select);

// accept(Token::SEMI);

// return stmt;
//     return nullptr;
// }

/*
 * zhujun [455910092@qq.com]
 * parse spstatement
 */
SQLStatement_ptr MySqlStatementParser::parseSpStatement()
{
  // update
  if (lexer->token()->name->c_str() == (Token::UPDATE.name->c_str()))
  {
    // return parseUpdateStatement();
  }

  // create
  if (lexer->token()->name->c_str() == (Token::CREATE.name->c_str()))
  {
    return parseCreate();
  }

  // insert
  if (lexer->token()->name->c_str() == Token::INSERT.name->c_str())
  {
    return parseInsert();
  }

  // delete
  if (lexer->token()->name->c_str() == (Token::DELETE.name->c_str()))
  {
    // return parseDeleteStatement();
  }

  // begin
  if (lexer->token()->name->c_str() == Token::BEGIN.name->c_str())
  {
    return this->parseBlock();
  }

  // select
  if (lexer->token()->name->c_str() == Token::LPAREN.name->c_str())
  {
    Lexer_SavePoint_ptr savePoint = lexer->markOut();
    lexer->nextToken();

    if (lexer->token()->name->c_str() == Token::SELECT.name->c_str())
    {
      lexer->reset(savePoint);
      return this->parseSelect();
    }
    else
    {
      throw new ParserException(make_string_ptr("TODO. " + encode_util::UnicodeToUTF8(lexer->info())));
    }
  }
  // assign statement
  if (lexer->token()->name->c_str() == Token::SET.name->c_str())
  {
    // return parseAssign();
  }

  throw new ParserException(make_string_ptr("error sp_statement. " + encode_util::UnicodeToUTF8(lexer->info())));
}

/*
 * 定义异常处理程序
 *
 * @author zhujun [455910092@qq.com]
 * 2016-04-16
 */
// MySqlDeclareHandlerStatement* MySqlStatementParser::parseDeclareHandler() {
// DECLARE handler_type HANDLER FOR condition_value[,...] sp_statement
// handler_type 取值为 CONTINUE | EXIT | UNDO
// condition_value 取值为 SQLWARNING | NOT FOUND | SQLEXCEPTION | SQLSTATE value(异常码 e.g 1062)

// MySqlDeclareHandlerStatement* stmt = new MySqlDeclareHandlerStatement();
// accept(Token::DECLARE);
// //string_ptr  handlerType = exprParser->name().getSimpleName();
// if (lexer->token()->name->c_str() == Token::CONTINUE) {
//     stmt->setHandleType(MySqlHandlerType.CONTINUE);
// } else if (lexer->token()->name->c_str() == Token::EXIT) {
//     stmt->setHandleType(MySqlHandlerType.CONTINUE);
// } else if (lexer->token()->name->c_str() == Token::UNDO) {
//     stmt->setHandleType(MySqlHandlerType.CONTINUE);
// } else {
//     throw new ParserException("unkown handle type. " + lexer->info());
// }
// lexer->nextToken();

// acceptIdentifier("HANDLER");

// accept(Token::FOR);

// for (; ; ) {
//     string_ptr  tokenName = lexer->stringVal();
//     ConditionValue condition = new ConditionValue();

//     if (StringUtils::iequals(tokenName, "NOT")) {
//         //for 'NOT FOUND'
//         lexer->nextToken();
//         acceptIdentifier("FOUND");
//         condition.setType(ConditionType.SYSTEM);
//         condition.setValue("NOT FOUND");

//     } else if (StringUtils::iequals(tokenName, "SQLSTATE")) {
//         //for SQLSTATE (SQLSTATE '10001')
//         condition.setType(ConditionType.SQLSTATE);
//         lexer->nextToken();
//         //condition.setValue(lexer->stringVal());
//         //lexer->nextToken();
//         condition.setValue(exprParser->name().toString());
//     } else if (lexer->identifierEquals("SQLEXCEPTION")) {
//         //for SQLEXCEPTION
//         condition.setType(ConditionType.SYSTEM);
//         condition.setValue(lexer->stringVal());
//         lexer->nextToken();
//     } else if (lexer->identifierEquals("SQLWARNING")) {
//         //for SQLWARNING
//         condition.setType(ConditionType.SYSTEM);
//         condition.setValue(lexer->stringVal());
//         lexer->nextToken();
//     } else { //for condition_name or mysql_error_code
//         if (lexer->token()->name->c_str() == Token::LITERAL_INT) {
//             condition.setType(ConditionType.MYSQL_ERROR_CODE);
//             condition.setValue(lexer->integerValue().toString());
//         } else {
//             condition.setType(ConditionType.SELF);
//             condition.setValue(tokenName);
//         }
//         lexer->nextToken();
//     }
//     stmt->getConditionValues().add(condition);
//     if (lexer->token()->name->c_str() == Token::COMMA.name->c_str()) {
//         accept(Token::COMMA);
//         continue;
//     } else if (lexer->token()->name->c_str() != Token::XEOF) {
//         break;
//     } else {
//         throw new ParserException("declare handle not eof");
//     }
// }

// stmt->setSpStatement(parseSpStatement());

// if (!(stmt->getSpStatement() instanceof SQLBlockStatement)) {
//     accept(Token::SEMI);
// }

// return stmt;
//     return nullptr;
// }

/*
 * zhujun [455910092@qq.com]
 * 2016-04-17
 * 定义条件
 */
// MySqlDeclareConditionStatement* MySqlStatementParser::parseDeclareCondition() {
// MySqlDeclareConditionStatement* stmt = new MySqlDeclareConditionStatement();
// accept(Token::DECLARE);

// stmt->setConditionName(exprParser->name().toString());

// accept(Token::CONDITION);

// accept(Token::FOR);

// string_ptr  tokenName = lexer->stringVal();
// ConditionValue* condition = new ConditionValue();
// if (StringUtils::iequals(tokenName, "SQLSTATE")) { //for SQLSTATE (SQLSTATE '10001')
//     condition.setType(ConditionType.SQLSTATE);
//     lexer->nextToken();
//     condition.setValue(exprParser->name().toString());
// } else if (lexer->token()->name->c_str() == Token::LITERAL_INT) {
//     condition.setType(ConditionType.MYSQL_ERROR_CODE);
//     condition.setValue(lexer->integerValue().toString());
//     lexer->nextToken();
// } else {
//     throw new ParserException("declare condition grammer error. " + lexer->info());
// }

// stmt->setConditionValue(condition);

// accept(Token::SEMI);

// return stmt;
//     return nullptr;
// }

SQLStatement_ptr MySqlStatementParser::parseFlashback()
{
  // MySqlFlashbackStatement* stmt = new MySqlFlashbackStatement();
  // acceptIdentifier("FLASHBACK");
  // accept(Token::TABLE);

  // SQLName_ptr  name = this->exprParser->name();
  // stmt->setName(name);
  // accept(Token::TO);
  // acceptIdentifier("BEFORE");
  // accept(Token::DROP);

  // if (lexer->identifierEquals(FnvHash::Constants::RENAME)) {
  //     lexer->nextToken();
  //     accept(Token::TO);
  //     SQLName_ptr  to = this->exprParser->name();
  //     stmt->setRenameTo(to);
  // }

  // return stmt;
  return nullptr;
}

time_t MySqlStatementParser::getCurrentTimestamp()
{
  return now;
}

time_t MySqlStatementParser::getCurrentDate()
{
  return currentDate;
}

MySqlCreateTableParser *MySqlStatementParser::getSQLCreateTableParser()
{
  return new MySqlCreateTableParser(this->exprParser);
}

SQLStatement_ptr MySqlStatementParser::parseCopy()
{
  acceptIdentifier("COPY");

  // SQLCopyFromStatement* stmt = new SQLCopyFromStatement();

  // SQLExpr_ptr table = this->exprParser->name();
  // stmt->setTable(new SQLExprTableSource(table));

  // if (lexer->token()->name->c_str() == Token::LPAREN.name->c_str()) {
  //     lexer->nextToken();
  //     this->exprParser->names(stmt->getColumns(), stmt);
  //     accept(Token::RPAREN);
  // }

  // if (lexer->token()->name->c_str() == Token::PARTITION.name->c_str()) {
  //     lexer->nextToken();
  //     this->exprParser->parseAssignItem(stmt->getPartitions(), stmt);
  // }

  // accept(Token::FROM);
  // SQLExpr_ptr from = this->exprParser->getExpr();
  // stmt->setFrom(from);

  // if (lexer->identifierEquals(FnvHash::Constants::CREDENTIALS)) {
  //     lexer->nextToken();

  //     for (; ; ) {
  //         if (lexer->identifierEquals(FnvHash::Constants::ACCESS_KEY_ID)) {
  //             lexer->nextToken();
  //             SQLExpr_ptr accessKeyId = this->exprParser->primary();
  //             stmt->setAccessKeyId(accessKeyId);
  //         } else if (lexer->identifierEquals(FnvHash::Constants::ACCESS_KEY_SECRET)) {
  //             lexer->nextToken();
  //             SQLExpr_ptr accessKeySecret = this->exprParser->primary();
  //             stmt->setAccessKeySecret(accessKeySecret);
  //         } else {
  //             break;
  //         }
  //     }
  // }

  // if (lexer->token()->name->c_str() == Token::WITH.name->c_str()) {
  //     lexer->nextToken();
  //     accept(Token::LPAREN);
  //     for (; ; ) {
  //         SQLName_ptr  name = this->exprParser->name();
  //         if (lexer->token()->name->c_str() == Token::EQ.name->c_str()) {
  //             lexer->nextToken();
  //         }
  //         SQLExpr_ptr value = this->exprParser->getExpr();
  //         SQLAssignItem item = new SQLAssignItem(name, value);
  //         item.setParent(stmt);
  //         stmt->getOptions().add(item);
  //         if (lexer->token()->name->c_str() == Token::COMMA.name->c_str()) {
  //             lexer->nextToken();
  //             continue;
  //         }
  //         break;
  //     }
  //     accept(Token::RPAREN);
  // }
  // return stmt;
  return nullptr;
}
